Linux 套接字编程中 bind 错误:bind fail:Address already in use 解决方法

来源:互联网 发布:淘宝店免费开店要钱吗 编辑:程序博客网 时间:2024/05/21 21:02

最近在学Linux 网络编程,调试TCP并发服务器时遇到一个问题,当我连接上一个或多个客户端后,用 CTRL+C 关闭进程后,重新打开进程就发生错误了:bind fail:Address already in use

地址被占用???

开始我以为是套接字描述符未关闭,添加代码在发生错误时关闭掉套接字描述符还是不行。

上网查了才发现是原来是套接字状态未配置,IBM官网上有较为详细的解释Linux 套接字编程中的 5 个隐患

下面截取文中一段相关内容:

隐患 3.地址使用错误(EADDRINUSE)

您可以使用 bind API 函数来绑定一个地址(一个接口和一个端口)到一个套接字端点。可以在服务器设置中使用这个函数,以便限制可能有连接到来的接口。也可以在客户端设置中使用这个函数,以便限制应当供出去的连接所使用的接口。bind 最常见的用法是关联端口号和服务器,并使用通配符地址(INADDR_ANY),它允许任何接口为到来的连接所使用。

bind 普遍遭遇的问题是试图绑定一个已经在使用的端口。该陷阱是也许没有活动的套接字存在,但仍然禁止绑定端口(bind 返回EADDRINUSE),它由 TCP 套接字状态 TIME_WAIT 引起。该状态在套接字关闭后约保留 2 到 4 分钟。在 TIME_WAIT 状态退出之后,套接字被删除,该地址才能被重新绑定而不出问题。

等待 TIME_WAIT 结束可能是令人恼火的一件事,特别是如果您正在开发一个套接字服务器,就需要停止服务器来做一些改动,然后重启。幸运的是,有方法可以避开 TIME_WAIT 状态。可以给套接字应用 SO_REUSEADDR 套接字选项,以便端口可以马上重用。


原来是TCP 套接字状态 TIME_WAIT 引起的,解决方法就是用 setsockopt 函数对套接字状态进行配置:

[objc] view plain copy
  1. int iSockOptVal = 1;  
  2. if (setsockopt(iSockFd, SOL_SOCKET, SO_REUSEADDR, &iSockOptVal, sizeof(iSockOptVal)) == -1) {  
  3.     perror("setsockopt fail");  
  4.     close(iSockFd);  
  5.     exit(EXIT_FAILURE);  
  6. }  

上述代码中,函数原型为 setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen),

参数s为 socket 描述符;

level 代表预设置的网络层,一般设置为 SOLSOCKET 以存取 socket 层;

optname 代表预设置的选项,设为 SO_REUSEADDR 表示允许在 bind() 时本地地址可重复复用;

optval 代表预设置的值的指针,在这里传入1表示允许地址重复,传入0表示不允许地址重复; 

optlen 则为 optval 的长度。

关于 setsockopt 函数的配置参数的一些解析及应用可参考这篇文章:setsockopt 用法详解

大笑

附上我的TCP并发服务器测试代码:

   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <time.h>
#include <pthread.h>
#include <unistd.h>
static void *clientHandle(void *arg);
int main(int argc, char *argv[])
{
int iNetPort = 0;
int iSockFd = 0;
int iClientFd = 0;
int iSerAddrLen = 0;
int iSockOptVal = 1;
pthread_t iThreadId = 0;
struct sockaddr_in SERVERADDR;
/*
* 输入参数检查
*/
if (argc != 2) {
printf("input one arg\r\n");
exit(EXIT_FAILURE);
}
iNetPort = atoi(argv[1]);
/*
* 建立套接字描述符
*/
if ((iSockFd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("socket fail");
exit(EXIT_FAILURE);
}
/*
* 设置套接字状态
*/
if (setsockopt(iSockFd, SOL_SOCKET, SO_REUSEADDR, &iSockOptVal, sizeof(iSockOptVal)) == -1) {
perror("setsockopt fail");
close(iSockFd);
exit(EXIT_FAILURE);
}
/*
* 绑定服务器与套接字
*/
bzero(&SERVERADDR, sizeof(SERVERADDR));
SERVERADDR.sin_family = AF_INET;
SERVERADDR.sin_port = htons(iNetPort);
SERVERADDR.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(iSockFd, (struct sockaddr *)&SERVERADDR, sizeof(SERVERADDR)) == -1) {
perror("bind fail");
close(iSockFd);
exit(EXIT_FAILURE);
}
/*
* 监听指定端口,最大连接5个客户端
*/
if (listen(iSockFd, 5) == -1) {
perror("listen fail");
close(iSockFd);
exit(EXIT_FAILURE);
}
/*
* 为每个连接的客户端建立一个线程
*/
while(1) {
iSerAddrLen = sizeof(SERVERADDR);
if ((iClientFd = accept(iSockFd, (struct sockaddr *)&SERVERADDR, &iSerAddrLen)) == -1) {
if (errno == EINTR) {
close(iSockFd);
continue;
}
else {
perror("accept fail");
close(iSockFd);
exit(EXIT_FAILURE);
}
}
/*
* 打印客户地址
*/
printf("Client IP:%s\r\n",inet_ntoa(SERVERADDR.sin_addr));
printf("Client PORT:%d\r\n",ntohs(SERVERADDR.sin_port));
/*
* 新建一个线程
*/
if (pthread_create(&iThreadId, NULL, clientHandle, &iClientFd) == -1) {
perror("pthread_create fail");
close(iSockFd);
close(iClientFd);
exit(EXIT_FAILURE);
}
}
close(iSockFd);
close(iClientFd);
exit(EXIT_SUCCESS);
}
static void *clientHandle(void *arg)
{
int iClientFd = *(int *)arg;
int iReadByteSize = 0;
char cRcvSndBuf[100];
time_t tTime;
printf("Client Fd:%d\r\n",iClientFd);
while (1) {
/*
* 接受客户端信息
*/
memset(cRcvSndBuf, 0, sizeof(cRcvSndBuf));
if((iReadByteSize = read(iClientFd, cRcvSndBuf, sizeof(cRcvSndBuf))) == -1) {
perror("read fail");
close(iClientFd);
return 0;
}
else if (iReadByteSize == 0) {
printf("Client not connect");
close(iClientFd);
return 0;
}
if (strncmp(cRcvSndBuf, "end", 3) == 0) {
printf("thread close:%d\r\n", iClientFd);
close(iClientFd);
return 0;
}
else if(strncmp(cRcvSndBuf, "time", 4) == 0) {
tTime = time(NULL);
sprintf(cRcvSndBuf, "TIME:%s", ctime(&tTime));
}
else {
cRcvSndBuf[iReadByteSize] = '\n';
cRcvSndBuf[iReadByteSize+1] = '\0';
}
write(iClientFd, cRcvSndBuf, strlen(cRcvSndBuf));
}
return 0;
}转载:http://blog.csdn.net/bruno_mars/article/details/52384623
阅读全文
0 0
原创粉丝点击