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

转载: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 4096

int 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,当使用evconnlistener_new_bind函数时,可能会遇到"Address already in use"错误。这个错误表示所尝试绑定的端口已经被其他进程占用。 为了解决这个问题,可以使用setsockopt函数来设置端口复用。具体步骤如下: 1. 创建一个socket文件描述符。 2. 设置SO_REUSEADDR选项,允许地址复用。 3. 绑定socket到指定的地址和端口。 下面是一个示例代码,演示了如何解决"Address already in use"错误: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main() { int sockfd; struct sockaddr_in addr; // 创建socket sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket"); exit(EXIT_FAILURE); } // 设置SO_REUSEADDR选项 int opt = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) { perror("setsockopt"); exit(EXIT_FAILURE); } // 绑定socket到指定的地址和端口 memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(8080); addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) { perror("bind"); exit(EXIT_FAILURE); } printf("Bind successful!n"); return 0; } ``` 这段代码首先创建了一个socket文件描述符,然后设置了SO_REUSEADDR选项,最后绑定socket到指定的地址和端口。通过设置SO_REUSEADDR选项,可以允许地址复用,从而解决"Address already in use"错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值