客户端代码:
int main(int argc, char* argv[]){
int ilRet = 0;
while(1){
struct sockaddr_in slAddr;
bzero(&slAddr, sizeof(slAddr));
slAddr.sin_family = AF_INET;
slAddr.sin_port = htons(44445);
slAddr.sin_addr.s_addr = inet_addr("172.17.236.122");
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd) {
printf("socket()fail, errno[%d], errmsg[%s]\n", errno, strerror(errno));
return -1;
}
printf("socket ok!\n");
/*const int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1 ) {
printf("setsockopt sockfd[%d] fail, errno[%d], errmsg[%s]\n",
sockfd, errno,strerror(errno));
return -1;
}
printf("setsockopt ok!\n");*/
printf("connect!\n");
unsigned int len = sizeof(slAddr);
if (connect(sockfd, (struct sockaddr*)&slAddr, len) == 0){
printf("connect ok!\n");
sleep(10000000);
char buf[100];
if(recv(sockfd,buf, 100, 0) <= 0){
printf("recv error!\n");
close(sockfd);
continue;
}
break;
}
else{
printf("connect fail, errno[%d], errmsg[%s]\n", errno, strerror(errno));
}
sleep(1);
}
}
启动客户端连接某主机,连接成功:
netstat -an |grep 44445
tcp 0 0 172.18.64.64:51365 172.17.236.122:44445 ESTABLISHED
取出其中的随机端口51365
服务器代码:
int main(int argc, char* argv[]){
int ilRet = 0;
int fd = 0;
struct sockaddr_in slAddr;
bzero(&slAddr, sizeof(slAddr));
slAddr.sin_family = AF_INET;
slAddr.sin_port = htons(51365);
//slAddr.sin_addr.s_addr = htonl(INADDR_ANY);
slAddr.sin_addr.s_addr = inet_addr("172.18.64.64");
/* inet_pton(AF_INET, paIP, &slAddr.sin_addr); */
struct sockaddr_in pAddr;
bzero(&pAddr, sizeof(pAddr));
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd) {
printf("socket()fail, errno[%d], errmsg[%s]\n", errno, strerror(errno));
return -1;
}
printf("socket ok!\n");
int on = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0 ) {
printf("setsockopt sockfd[%d] fail, errno[%d], errmsg[%s]\n",
sockfd, errno,strerror(errno));
return -1;
}
printf("setsockopt ok!\n");
if (bind(sockfd, (struct sockaddr *)&slAddr, sizeof(slAddr)) != 0) {
printf("bind()sockfd[%d]fail, errno[%d], errmsg[%s]\n",
sockfd, errno,strerror(errno));
close(sockfd);
return -1;
}
printf("bind ok!\n");
if (listen(sockfd, 5) != 0) {
close(sockfd);
printf("listen fail, errno[%d], errmsg[%s]\n", errno,strerror(errno));
return -1;
}
printf("listen ok!\n");
/*后面省略1000字*/
服务器端监听端口填写成客户端的随机端口,在客户端启动的机器上(同一台机器)启动服务端
报错:
socket ok!
setsockopt ok!
bind()sockfd[3]fail, errno[98], errmsg[Address already in use]
再次修改客户端的代码,将客户端代码中
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)的注释打开,重新启动客户端和服务端程序,服务端正常监听:
socket ok!
setsockopt ok!
bind ok!
listen ok!
netstat -an |grep 51365
tcp 0 0 172.18.64.64:51365 0.0.0.0:* LISTEN
tcp 0 0 172.18.64.64:51365 172.17.236.122:44445 ESTABLISHED
系统版本信息:
cat /etc/issue
Welcome to SUSE Linux Enterprise Server 11 SP2 (x86_64) - Kernel \r (\l).
lsb_release -a
LSB Version: core-2.0-noarch:core-3.2-noarch:core-4.0-noarch:core-2.0-x86_64:core-3.2-x86_64:core-4.0-x86_64:desktop-4.0-amd64:desktop-4.0-noarch:graphics-2.0-amd64:graphics-2.0-noarch:graphics-3.2-amd64:graphics-3.2-noarch:graphics-4.0-amd64:graphics-4.0-noarch
Distributor ID: SUSE LINUX
Description: SUSE Linux Enterprise Server 11 (x86_64)
Release: 11
Codename: n/a
不解的问题:
1、随机端口被占用,比如说45000,那么在45000上的监听就起不来么?那这么说所有的监听端口是不是都要在随机端口的范围下面才合适?有书上这么说么,比如说UNP或者TCP/IP详解,没见到。。
2、SO_REUSEADDR我所理解就是解决服务端TIME_WAIT的问题(大部分应用都是这么用的),今天的这个例子怎么解释,用UNP里面SO_REUSEADDR应用说明的四条中的那一条解释合适?
球大侠现身。。。
7 个解决方案
#1
SO_REUSERPORT是可以多进程bind同一个Port的,但只有linux3.x内核才刚刚支持这个选项,之前此选项是不起作用的。
SO_REUSERADDR是复用TIME_WAIT的,没问题。
SO_REUSERADDR是复用TIME_WAIT的,没问题。
#2
多提一句吧,windows的socket早就支持SO_REUSERPORT这个功能了,很多木马会扫除比如QQ正在使用的通讯端口,然后也bind到这个端口上,从而避免杀软发现自己。
你只要知道TCP是4元组,那么肯定知道在本地bind 无数次同一个Port是毫无问题的,只是linux内核一直把SO_REUSERPORT这个选项别扭着没实现。
#3
多谢版主出马,SO_REUSEPORT目前并不支持;
问题依旧:
1、随机端口被占用,比如说51365,那么在51365上的监听就起不来么?(这个是我碰到的问题的根源)
那这么说所有的监听端口是不是都要在随机端口的范围下面才合适?
netstat -an |grep 44445
tcp 0 0 172.18.64.64:51365 172.17.236.122:44445 ESTABLISHED
44445是我主机的一个监听,实验主机用的客户端程序连接到44445,产生随机端口51365
然后悲剧发生了:实验主机上的服务端程序绑定51365失败了。。。
socket ok!
setsockopt ok!
bind()sockfd[3]fail, errno[98], errmsg[Address already in use]
主要是这个怎么解释???
2、我在实验主机的客户端connect之前SO_REUSEADDR,问题就解决了,相当于clt和svr都设置了SO_REUSEADDR才可以。。。
当然,作为服务端程序,第一次碰到跟别人的随机端口冲突,也不能指望别人调用之前SO_REUSEADDR,更不能寄希望系统不会分配到跟我们监听端口一样的随机端口;
这个该怎么解释??
这个问题最终是可以解决的,就是listen在随机端口范围以下的端口就ok了;
但是1和2是为什么????
问题依旧:
1、随机端口被占用,比如说51365,那么在51365上的监听就起不来么?(这个是我碰到的问题的根源)
那这么说所有的监听端口是不是都要在随机端口的范围下面才合适?
netstat -an |grep 44445
tcp 0 0 172.18.64.64:51365 172.17.236.122:44445 ESTABLISHED
44445是我主机的一个监听,实验主机用的客户端程序连接到44445,产生随机端口51365
然后悲剧发生了:实验主机上的服务端程序绑定51365失败了。。。
socket ok!
setsockopt ok!
bind()sockfd[3]fail, errno[98], errmsg[Address already in use]
主要是这个怎么解释???
2、我在实验主机的客户端connect之前SO_REUSEADDR,问题就解决了,相当于clt和svr都设置了SO_REUSEADDR才可以。。。
当然,作为服务端程序,第一次碰到跟别人的随机端口冲突,也不能指望别人调用之前SO_REUSEADDR,更不能寄希望系统不会分配到跟我们监听端口一样的随机端口;
这个该怎么解释??
这个问题最终是可以解决的,就是listen在随机端口范围以下的端口就ok了;
但是1和2是为什么????
#4
在SO_REUSEPORT尚未普及的情况下, 内核中的每个port只应属于一个process,但是有两个特例:
1,bind后fork的。
2,listen后accept的。
楼主问题1:既然随机端口被占用着,你bind肯定是失败的,除非有REUSERPORT选项。
楼主问题2:你是说系统会给你分配到一个已经bind的端口?不太可能。
1,bind后fork的。
2,listen后accept的。
楼主问题1:既然随机端口被占用着,你bind肯定是失败的,除非有REUSERPORT选项。
楼主问题2:你是说系统会给你分配到一个已经bind的端口?不太可能。
#5
版主说要用REUSERPORT选项来实现,但是我的这个例子中用SO_REUSEADDR已经可以解决这个冲突问题了,但是苦于在UNP上SO_REUSEADDR的四条用法中找不到对应的解释:
SO_REUSEADDR可以用在以下四种情况下:
(摘自《Unix网络编程》卷一,即UNPv1)
1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启
动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但
每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可
以测试这种情况。
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个soc
ket绑定的ip地址不同。这和2很相似,区别请看UNPv1。
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的
多播,不用于TCP。
我所纠结的问题在这儿:
1、既然存在这种跟随机端口冲突的问题,那我的监听端口该设定为多少才能保证不会跟随机端口冲突,就是svr监听端口的取值范围问题
2、从上述实验中只有clt和svr都设置了SO_REUSEADDR,绑定在该端口上的bind操作才会成功,只要一个没有设置就errno98,如何解释,必须要clt也设置SO_REUSEADDR;
3、实际上我在AIX上也做过实验,AIX只需要svr设置了SO_REUSEADDR就可以bind在一个已经分配了的随机端口上,还是想知道如何解释这个实现机制。
SO_REUSEADDR可以用在以下四种情况下:
(摘自《Unix网络编程》卷一,即UNPv1)
1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启
动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但
每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可
以测试这种情况。
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个soc
ket绑定的ip地址不同。这和2很相似,区别请看UNPv1。
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的
多播,不用于TCP。
我所纠结的问题在这儿:
1、既然存在这种跟随机端口冲突的问题,那我的监听端口该设定为多少才能保证不会跟随机端口冲突,就是svr监听端口的取值范围问题
2、从上述实验中只有clt和svr都设置了SO_REUSEADDR,绑定在该端口上的bind操作才会成功,只要一个没有设置就errno98,如何解释,必须要clt也设置SO_REUSEADDR;
3、实际上我在AIX上也做过实验,AIX只需要svr设置了SO_REUSEADDR就可以bind在一个已经分配了的随机端口上,还是想知道如何解释这个实现机制。
#6
再说一下实验过程吧:
SUSE Linux :
1、客户端socket connect 172.17.233.122:44445
2、连接成功 tcp 0 0 172.18.64.64:54050 172.17.236.122:44445 ESTABLISHED
3、服务端socket setsockopt(SO_REUSEADDR) bind(172.18.64.64:54050) listen accept
4、启动服务端,bind失败,errno98
1、客户端socket setsockopt(SO_REUSEADDR) connect 172.17.233.122:44445
2、连接成功 tcp 0 0 172.18.64.64:54052 172.17.236.122:44445 ESTABLISHED
3、服务端socket setsockopt(SO_REUSEADDR) bind(172.18.64.64:54052) listen accept
4、启动服务端,bind成功
IBM AIX:
上述两种情况都bind成功,只要svr设置了setsockopt(SO_REUSEADDR);
上述两种情况都bind失败,只要svr没有设置setsockopt(SO_REUSEADDR);
SUSE Linux :
1、客户端socket connect 172.17.233.122:44445
2、连接成功 tcp 0 0 172.18.64.64:54050 172.17.236.122:44445 ESTABLISHED
3、服务端socket setsockopt(SO_REUSEADDR) bind(172.18.64.64:54050) listen accept
4、启动服务端,bind失败,errno98
1、客户端socket setsockopt(SO_REUSEADDR) connect 172.17.233.122:44445
2、连接成功 tcp 0 0 172.18.64.64:54052 172.17.236.122:44445 ESTABLISHED
3、服务端socket setsockopt(SO_REUSEADDR) bind(172.18.64.64:54052) listen accept
4、启动服务端,bind成功
IBM AIX:
上述两种情况都bind成功,只要svr设置了setsockopt(SO_REUSEADDR);
上述两种情况都bind失败,只要svr没有设置setsockopt(SO_REUSEADDR);
#7
自己顶一个。。。
#1
SO_REUSERPORT是可以多进程bind同一个Port的,但只有linux3.x内核才刚刚支持这个选项,之前此选项是不起作用的。
SO_REUSERADDR是复用TIME_WAIT的,没问题。
SO_REUSERADDR是复用TIME_WAIT的,没问题。
#2
多提一句吧,windows的socket早就支持SO_REUSERPORT这个功能了,很多木马会扫除比如QQ正在使用的通讯端口,然后也bind到这个端口上,从而避免杀软发现自己。
你只要知道TCP是4元组,那么肯定知道在本地bind 无数次同一个Port是毫无问题的,只是linux内核一直把SO_REUSERPORT这个选项别扭着没实现。
#3
多谢版主出马,SO_REUSEPORT目前并不支持;
问题依旧:
1、随机端口被占用,比如说51365,那么在51365上的监听就起不来么?(这个是我碰到的问题的根源)
那这么说所有的监听端口是不是都要在随机端口的范围下面才合适?
netstat -an |grep 44445
tcp 0 0 172.18.64.64:51365 172.17.236.122:44445 ESTABLISHED
44445是我主机的一个监听,实验主机用的客户端程序连接到44445,产生随机端口51365
然后悲剧发生了:实验主机上的服务端程序绑定51365失败了。。。
socket ok!
setsockopt ok!
bind()sockfd[3]fail, errno[98], errmsg[Address already in use]
主要是这个怎么解释???
2、我在实验主机的客户端connect之前SO_REUSEADDR,问题就解决了,相当于clt和svr都设置了SO_REUSEADDR才可以。。。
当然,作为服务端程序,第一次碰到跟别人的随机端口冲突,也不能指望别人调用之前SO_REUSEADDR,更不能寄希望系统不会分配到跟我们监听端口一样的随机端口;
这个该怎么解释??
这个问题最终是可以解决的,就是listen在随机端口范围以下的端口就ok了;
但是1和2是为什么????
问题依旧:
1、随机端口被占用,比如说51365,那么在51365上的监听就起不来么?(这个是我碰到的问题的根源)
那这么说所有的监听端口是不是都要在随机端口的范围下面才合适?
netstat -an |grep 44445
tcp 0 0 172.18.64.64:51365 172.17.236.122:44445 ESTABLISHED
44445是我主机的一个监听,实验主机用的客户端程序连接到44445,产生随机端口51365
然后悲剧发生了:实验主机上的服务端程序绑定51365失败了。。。
socket ok!
setsockopt ok!
bind()sockfd[3]fail, errno[98], errmsg[Address already in use]
主要是这个怎么解释???
2、我在实验主机的客户端connect之前SO_REUSEADDR,问题就解决了,相当于clt和svr都设置了SO_REUSEADDR才可以。。。
当然,作为服务端程序,第一次碰到跟别人的随机端口冲突,也不能指望别人调用之前SO_REUSEADDR,更不能寄希望系统不会分配到跟我们监听端口一样的随机端口;
这个该怎么解释??
这个问题最终是可以解决的,就是listen在随机端口范围以下的端口就ok了;
但是1和2是为什么????
#4
在SO_REUSEPORT尚未普及的情况下, 内核中的每个port只应属于一个process,但是有两个特例:
1,bind后fork的。
2,listen后accept的。
楼主问题1:既然随机端口被占用着,你bind肯定是失败的,除非有REUSERPORT选项。
楼主问题2:你是说系统会给你分配到一个已经bind的端口?不太可能。
1,bind后fork的。
2,listen后accept的。
楼主问题1:既然随机端口被占用着,你bind肯定是失败的,除非有REUSERPORT选项。
楼主问题2:你是说系统会给你分配到一个已经bind的端口?不太可能。
#5
版主说要用REUSERPORT选项来实现,但是我的这个例子中用SO_REUSEADDR已经可以解决这个冲突问题了,但是苦于在UNP上SO_REUSEADDR的四条用法中找不到对应的解释:
SO_REUSEADDR可以用在以下四种情况下:
(摘自《Unix网络编程》卷一,即UNPv1)
1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启
动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但
每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可
以测试这种情况。
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个soc
ket绑定的ip地址不同。这和2很相似,区别请看UNPv1。
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的
多播,不用于TCP。
我所纠结的问题在这儿:
1、既然存在这种跟随机端口冲突的问题,那我的监听端口该设定为多少才能保证不会跟随机端口冲突,就是svr监听端口的取值范围问题
2、从上述实验中只有clt和svr都设置了SO_REUSEADDR,绑定在该端口上的bind操作才会成功,只要一个没有设置就errno98,如何解释,必须要clt也设置SO_REUSEADDR;
3、实际上我在AIX上也做过实验,AIX只需要svr设置了SO_REUSEADDR就可以bind在一个已经分配了的随机端口上,还是想知道如何解释这个实现机制。
SO_REUSEADDR可以用在以下四种情况下:
(摘自《Unix网络编程》卷一,即UNPv1)
1、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启
动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
2、SO_REUSEADDR允许同一port上启动同一服务器的多个实例(多个进程)。但
每个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可
以测试这种情况。
3、SO_REUSEADDR允许单个进程绑定相同的端口到多个socket上,但每个soc
ket绑定的ip地址不同。这和2很相似,区别请看UNPv1。
4、SO_REUSEADDR允许完全相同的地址和端口的重复绑定。但这只用于UDP的
多播,不用于TCP。
我所纠结的问题在这儿:
1、既然存在这种跟随机端口冲突的问题,那我的监听端口该设定为多少才能保证不会跟随机端口冲突,就是svr监听端口的取值范围问题
2、从上述实验中只有clt和svr都设置了SO_REUSEADDR,绑定在该端口上的bind操作才会成功,只要一个没有设置就errno98,如何解释,必须要clt也设置SO_REUSEADDR;
3、实际上我在AIX上也做过实验,AIX只需要svr设置了SO_REUSEADDR就可以bind在一个已经分配了的随机端口上,还是想知道如何解释这个实现机制。
#6
再说一下实验过程吧:
SUSE Linux :
1、客户端socket connect 172.17.233.122:44445
2、连接成功 tcp 0 0 172.18.64.64:54050 172.17.236.122:44445 ESTABLISHED
3、服务端socket setsockopt(SO_REUSEADDR) bind(172.18.64.64:54050) listen accept
4、启动服务端,bind失败,errno98
1、客户端socket setsockopt(SO_REUSEADDR) connect 172.17.233.122:44445
2、连接成功 tcp 0 0 172.18.64.64:54052 172.17.236.122:44445 ESTABLISHED
3、服务端socket setsockopt(SO_REUSEADDR) bind(172.18.64.64:54052) listen accept
4、启动服务端,bind成功
IBM AIX:
上述两种情况都bind成功,只要svr设置了setsockopt(SO_REUSEADDR);
上述两种情况都bind失败,只要svr没有设置setsockopt(SO_REUSEADDR);
SUSE Linux :
1、客户端socket connect 172.17.233.122:44445
2、连接成功 tcp 0 0 172.18.64.64:54050 172.17.236.122:44445 ESTABLISHED
3、服务端socket setsockopt(SO_REUSEADDR) bind(172.18.64.64:54050) listen accept
4、启动服务端,bind失败,errno98
1、客户端socket setsockopt(SO_REUSEADDR) connect 172.17.233.122:44445
2、连接成功 tcp 0 0 172.18.64.64:54052 172.17.236.122:44445 ESTABLISHED
3、服务端socket setsockopt(SO_REUSEADDR) bind(172.18.64.64:54052) listen accept
4、启动服务端,bind成功
IBM AIX:
上述两种情况都bind成功,只要svr设置了setsockopt(SO_REUSEADDR);
上述两种情况都bind失败,只要svr没有设置setsockopt(SO_REUSEADDR);
#7
自己顶一个。。。