setsockopt()和getsockopt()函数—-解决地址不可复用,即Address already in use

来源:互联网 发布:微信html5游戏源码 编辑:程序博客网 时间:2024/06/06 03:49

转载:http://blog.163.com/xychenbaihu@yeah/blog/static/1322296552011215111017599/

    Linux所提供的socket库有一个错误(bug);此错误表现为你不能为一个套接字重新启动同一个端口号。           即:比如一个程序,在IP”192.168.1.234″和Port”12357″上创建了一个套接字。启动程序后,在recvfrom数据,我们用ctrl+z强制终止程序。               当我们重启程序时,被提示::                              Address already in use                   //绑定时发生的错误。    产生问题的原因是::            Linux内核在一个绑定套接字的进程结束后,从不把端口标记为未用。     解决问题的方法::            当套接字sockfd已经打开,即socket()创建套接字之后,使用setsockopt系统调用在这个sockfd上设定选项(options)。     Linux内核提供的系统调用::               #include <sys/types.h>               #include <sys/socket.h>               int  getsockopt(int sockfd,int level,int name,char *value,int optlen);               int  setsockopt(int scokfd,int level,int name,char *value,int *optlen);     参数详解::               sockfd            必须是一个已经打开的sockfd,setsockopt应该在socket()之后就调用。               level               是函数使用的协议标准(protocol level),Linux使用的是套接字,套接字                                      的标准表示是SOL_SOCKET,其次TCP/IP协议使用的是IPPROTO_TCP,                                      我们并不关心这个。               name               在套接字中的说明,比如:SO_REUSEADDR,就是表示端口可以复用。                                       SO_BROADCAST,就表示将sockfd设置为可以进行广播的fd。                                       man手册中,name的取值比较多,我们比较关系的就是上面的两个。               value               我们用setsockopt设置数据的地址,getsockopt将在这个地址上得到值。               optlen              设置value时,value的大小。    举例:: 要实现端口复用(重复使用,即解决Address already use)。            /*创建套接字*/            int   sockfd   =  socket(AF_INET,SOCK_DGRAM或这SOCK_STREAM,0);            /*设定参数的值,即上面value和optlen的值*/            int   opt = 1;            int   len  =  sizeof(opt);            /*设置套接字属性,实现复用*/            setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,len);   举例::                这里只举例setsockopt用来设置端口可以复用(重复使用的情况)的情况,         getsockopt的并没有举例。getsockopt,主要用来获取sockfd的一些opt信息。                getsockopt的例子,以后有机会再补充。

代码举例 src.c :: 按ctrl+c强行终止后,会出现端口不可用的程序(Address already use)

#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netdb.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <error.h>#include <unistd.h>#include <netinet/in.h>#define MAX_LINE 4096int main(int argc,char *argv[]){struct sockaddr_in srvaddr;struct sockaddr_in cltaddr;int socklen=sizeof(struct sockaddr_in);int sockfd;char msgbuf[MAX_LINE];int msglen; int opt = 1;int len = sizeof(opt);srvaddr.sin_family = AF_INET;srvaddr.sin_addr.s_addr = inet_addr(“172.25.81.16”);srvaddr.sin_port = htons(12357);bzero(srvaddr.sin_zero,sizeof(srvaddr.sin_zero)); sockfd = socket(AF_INET,SOCK_DGRAM,0);if(sockfd == -1){perror(“creat socket fd fail:”);exit(1);}if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,len)==-1){perror(“setsockopt fail:”);close(sockfd);exit(1);} if(bind(sockfd,(struct sockaddr *)&srvaddr,sizeof(struct sockaddr_in))==-1){perror(“bind socket fd fail:”);close(sockfd);exit(1);} memset(msgbuf,0,MAX_LINE);msglen = recvfrom(sockfd,msgbuf,MAX_LINE,0,(struct sockaddr *)&cltaddr,&socklen);if(msglen < 0){perror(“recv data fail:”);close(sockfd);exit(1);}else{msgbuf[msglen] = ‘\0’;printf(“recv data from clt:%s\n”,msgbuf);memset(msgbuf,0,MAX_LINE);strcpy(msgbuf,”hello clt!”);sendto(sockfd,msgbuf,strlen(msgbuf),0,(struct sockaddr *)&cltaddr,socklen);close(sockfd);}return 0;}

编译成src,运行过程中,按ctrl+c,终止程序,重启时,端口可以复用(重复使用)。不会出现问题。

0 0
原创粉丝点击