




已阅读5页,还剩7页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux网络编程之绑定端口注意事项及端口复用所谓绑定(bind)是指别人连接我只能通过我所绑定的端口,相当于,我买了一个手机,别人要想联系我,必须要知道我的手机号码,这时候,我需要怎么办呢?我需要给手机插上电话卡,固定一个电话号码,这样别人就能通过这个电话号码联系我。手机插上电话卡,固定一个电话号码,类似于绑定(bind)的过程,绑定(bind)为了固定一个端口号,别的网络程序就可以找到这个端口号,找到这个端口号就能找到这个端口号所对应的网络应用程序。在网络编程里,通常都是在服务器里绑定(bind)端口,这并不是说客户端里不能绑定(bind)端口,但这里需要注意的是,一个网络应用程序只能绑定一个端口( 一个套接字只能 绑定一个端口 )。一个套接字不能同时绑定多个端口,如下:#include #include #include #include #include #include #include intmain(intargc,charchar*argv) charserver_ip30=10.221.20.12; intsockfd; sockfd=socket(AF_INET,SOCK_DGRAM,0);/创建UDP套接字 if(sockfd0) perror(socket); exit(-1); /初始化本地网络信息 structsockaddr_inmy_addr; bzero(&my_addr,sizeof(my_addr); my_addr.sin_family=AF_INET; my_addr.sin_port=htons(8000); my_addr.sin_addr.s_addr=htonl(INADDR_ANY); /第一次绑定端口8000 interr_log; err_log=bind(sockfd,(structsockaddr*)&my_addr,sizeof(my_addr); if(err_log!=0) perror(bind8000); close(sockfd); exit(-1); /又一次绑定别的端口9000,会绑定失败 my_addr.sin_port=htons(9000); err_log=bind(sockfd,(structsockaddr*)&my_addr,sizeof(my_addr); if(err_log!=0) perror(bind9000); close(sockfd); exit(-1); close(sockfd); return0; 程序编译运行后结果如下:如果客户端想绑定端口号,一定要调用发送信息函数之前绑定( bind )端口,因为在发送信息函数( sendto, 或 write ),系统会自动给当前网络程序分配一个随机端口号,这相当于随机绑定了一个端口号,这里只会分配一次,以后通信就以这个随机端口通信,我们再绑定端口号的话,就会绑定失败。如果我们放在发送信息函数( sendto, 或 write )之前绑定,那样程序将以我们绑定的端口号发送信息,不会再随机分配一个端口号。绑定失败例子( UDP )如下:#include #include #include #include #include #include #include intmain(intargc,charchar*argv) charserver_ip30=10.221.20.12; intsockfd; sockfd=socket(AF_INET,SOCK_DGRAM,0);/创建UDP套接字 if(sockfd0) perror(socket); exit(-1); structsockaddr_indest_addr; bzero(&dest_addr,sizeof(dest_addr); dest_addr.sin_family=AF_INET; dest_addr.sin_port=htons(8080);/服务器的端口 inet_pton(AF_INET,server_ip,&dest_addr.sin_addr); charsend_buf512=thisisfortest; /如果前面没有绑定端口,sendto()系统会随机分配一个端口 sendto(sockfd,send_buf,strlen(send_buf),0,(structsockaddr*)&dest_addr,sizeof(dest_addr);/发送数据 /初始化本地网络信息 structsockaddr_inmy_addr; bzero(&my_addr,sizeof(my_addr); my_addr.sin_family=AF_INET; my_addr.sin_port=htons(8000); my_addr.sin_addr.s_addr=htonl(INADDR_ANY); /sendto()后面绑定端口,绑定失败 interr_log; err_log=bind(sockfd,(structsockaddr*)&my_addr,sizeof(my_addr); if(err_log!=0) perror(bind8000); close(sockfd); exit(-1); close(sockfd); return0; 程序编译运行后结果如下:在上面提到:一个网络应用程序只能绑定一个端口( 一个套接字只能绑定一个端口 )。实际上,默认的情况下,如果一个网络应用程序的一个套接字 绑定了一个端口( 占用了 8000 ),这时候,别的套接字就无法使用这个端口( 8000 ), 验证例子如下:#include #include #include #include #include #include #include intmain(intargc,charchar*argv) intsockfd_one; interr_log; sockfd_one=socket(AF_INET,SOCK_DGRAM,0);/创建UDP套接字one if(sockfd_one0) perror(sockfd_one); exit(-1); /设置本地网络信息 structsockaddr_inmy_addr; bzero(&my_addr,sizeof(my_addr); my_addr.sin_family=AF_INET; my_addr.sin_port=htons(8000);/端口为8000 my_addr.sin_addr.s_addr=htonl(INADDR_ANY); /绑定,端口为8000 err_log=bind(sockfd_one,(structsockaddr*)&my_addr,sizeof(my_addr); if(err_log!=0) perror(bindsockfd_one); close(sockfd_one); exit(-1); intsockfd_two; sockfd_two=socket(AF_INET,SOCK_DGRAM,0);/创建UDP套接字two if(sockfd_two0) perror(sockfd_two); exit(-1); /新套接字sockfd_two,继续绑定8000端口,绑定失败 /因为8000端口已被占用,默认情况下,端口没有释放,无法绑定 err_log=bind(sockfd_two,(structsockaddr*)&my_addr,sizeof(my_addr); if(err_log!=0) perror(bindsockfd_two); close(sockfd_two); exit(-1); close(sockfd_one); close(sockfd_two); return0; 程序编译运行后结果如下:那如何让sockfd_one, sockfd_two两个套接字都能成功绑定8000端口呢?这时候就需要要到端口复用了。端口复用允许在一个应用程序可以把 n 个套接字绑在一个端口上而不出错。设置socket的SO_REUSEADDR选项,即可实现端口复用:intopt=1; /sockfd为需要端口复用的套接字 setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(constvoidvoid*)&opt,sizeof(opt);SO_REUSEADDR可以用在以下四种情况下。 (摘自Unix网络编程卷一,即UNPv1)1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可以测试这种情况。3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。这和2很相似,区别请看UNPv1。4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。需要注意的是,设置端口复用函数要在绑定之前调用,而且只要绑定到同一个端口的所有套接字都得设置复用:/sockfd_one,sockfd_two都要设置端口复用 /在sockfd_one绑定bind之前,设置其端口复用 intopt=1; setsockopt(sockfd_one,SOL_SOCKET,SO_REUSEADDR,(constvoidvoid*)&opt,sizeof(opt); err_log=bind(sockfd_one,(structsockaddr*)&my_addr,sizeof(my_addr); /在sockfd_two绑定bind之前,设置其端口复用 opt=1; setsockopt(sockfd_two,SOL_SOCKET,SO_REUSEADDR,(constvoidvoid*)&opt,sizeof(opt); err_log=bind(sockfd_two,(structsockaddr*)&my_addr,sizeof(my_addr);端口复用完整代码如下:#include #include #include #include #include #include #include intmain(intargc,charchar*argv) intsockfd_one; interr_log; sockfd_one=socket(AF_INET,SOCK_DGRAM,0);/创建UDP套接字one if(sockfd_one0) perror(sockfd_one); exit(-1); /设置本地网络信息 structsockaddr_inmy_addr; bzero(&my_addr,sizeof(my_addr); my_addr.sin_family=AF_INET; my_addr.sin_port=htons(8000);/端口为8000 my_addr.sin_addr.s_addr=htonl(INADDR_ANY); /在sockfd_one绑定bind之前,设置其端口复用 intopt=1; setsockopt(sockfd_one,SOL_SOCKET,SO_REUSEADDR, (constvoidvoid*)&opt,sizeof(opt); /绑定,端口为8000 err_log=bind(sockfd_one,(structsockaddr*)&my_addr,sizeof(my_addr); if(err_log!=0) perror(bindsockfd_one); close(sockfd_one); exit(-1); intsockfd_two; sockfd_two=socket(AF_INET,SOCK_DGRAM,0);/创建UDP套接字two if(sockfd_two0) perror(sockfd_two); exit(-1); /在sockfd_two绑定bind之前,设置其端口复用 opt=1; setsockopt(sockfd_two,SOL_SOCKET,SO_REUSEADDR, (constvoidvoid*)&opt,sizeof(opt); /新套接字sockfd_two,继续绑定8000端口,成功 err_log=bind(sockfd_two,(structsockaddr*)&my_addr,sizeof(my_addr); if(err_log!=0) perror(bindsockfd_two); close(sockfd_two); exit(-1); close(sockfd_one); close(sockfd_two); return0; 端口复用允许在一个应用程序可以把 n 个套接字绑在一个端口上而不出错。同时,这 n 个套接字发送信息都正常,没有问题。但是,这些套接字并不是所有都能读取信息,只有最后一个套接字会正常接收数据。下面,我们在之前的代码上,添加两个线程,分别负责接收sockfd_one,sockfd_two的信息:#include #include #include #include #include #include #include #include /线程1的回调函数 voidvoid*recv_one(voidvoid*arg) printf(=recv_one=n); intsockfd=(int)arg; while(1) intrecv_len; charrecv_buf512=; structsockaddr_inclient_addr; charcli_ipINET_ADDRSTRLEN=;/INET_ADDRSTRLEN=16 socklen_tcliaddr_len=sizeof(client_addr); recv_len=recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(structsockaddr*)&client_addr,&cliaddr_len); inet_ntop(AF_INET,&client_addr.sin_addr,cli_ip,INET_ADDRSTRLEN); printf(nip:%s,port:%dn,cli_ip,ntohs(client_addr.sin_port); printf(sockfd_one=data(%d):%sn,recv_len,recv_buf); returnNULL; /线程2的回调函数 voidvoid*recv_two(voidvoid*arg) printf(+recv_two+n); intsockfd=(int)arg; while(1) intrecv_len; charrecv_buf512=; structsockaddr_inclient_addr; charcli_ipINET_ADDRSTRLEN=;/INET_ADDRSTRLEN=16 socklen_tcliaddr_len=sizeof(client_addr); recv_len=recvfrom(sockfd,recv_buf,sizeof(recv_buf),0,(structsockaddr*)&client_addr,&cliaddr_len); inet_ntop(AF_INET,&client_addr.sin_addr,cli_ip,INET_ADDRSTRLEN); printf(nip:%s,port:%dn,cli_ip,ntohs(client_addr.sin_port); printf(sockfd_twodata(%d):%sn,recv_len,recv_buf); returnNULL; intmain(intargc,charchar*argv) interr_log; /sockfd_one intsockfd_one; sockfd_one=socket(AF_INET,SOCK_DGRAM,0);/创建UDP套接字one if(sockfd_one0) perror(sockfd_one); exit(-1); /设置本地网络信息 structsockaddr_inmy_addr; bzero(&my_addr,sizeof(my_addr); my_addr.sin_family=AF_INET; my_addr.sin_port=htons(8000);/端口为8000 my_addr.sin_addr.s_addr=htonl(INADDR_ANY); /在sockfd_one绑定bind之前,设置其端口复用 intopt=1; setsockopt(sockfd_one,SOL_SOCKET,SO_REUSEADDR, (constvoidvoid*)&opt,sizeof(opt); /绑定,端口为8000 err_log=bind(sockfd_one,(structsockaddr*)&my_addr,sizeof(my_addr); if(err_log!=0) perror(bindsockfd_one); close(sockfd_one); exit(-1); /接收信息线程1 pthread_ttid_one; pthread_create(&t
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025近距离沙石运输合同样本
- 网络安全设备配置与防护题库 (信息安全领域实战项目)
- 幼儿园课件-认识蔬菜
- 肺癌放疗饮食护理
- 人教版小学一年级数学下册期中试题
- 眩晕护理方案及护理常规
- 三角形全等的判定(复习)教学任务分析
- 视网膜毛细血管前小动脉阻塞的临床护理
- 山东省济宁市2025年高考模拟考试地理试题及答案(济宁三模)
- 浙江省宁波市镇海中学2025年5月第二次模拟考试语文试卷+答案
- 馅料间管理制度
- 2025年消防知识培训
- 上海健康医学院《SpringSpringMVCMyBais》2023-2024学年第二学期期末试卷
- 马尔代夫旅游介绍
- 保险行业档案管理培训
- 无废城市知识培训课件
- 2025煤炭矿区水土保持监测技术服务合同书
- 五金产品购销合同清单
- 2024年全国高中数学联赛(四川预赛)试题含答案
- 东北三省精准教学联盟2024-2025学年高三下学期3月联考地理试题(含答案)
- 2024北京西城区初一(下)期末道法试题和答案
评论
0/150
提交评论