导航
  • 主页
  • 系统维护与使用
  • 应用程序开发
  • 内核源代码
  • 驱动程序开发
  • CPU和硬件区
  • UNIX文化
  • Solaris
  • Power Linux
  • 问答

关于Linux下SO_REUSEADDR的疑问?

proad Java码农  2009-01-03 04:37:48
如下演示程序,程序目的是:
先准备好一个ServerSocket,监听端口8880,
然后建一个ClientSocket(受限于业务需要,必须在ServerSocket准备好后再建Client),也必须绑定同一端口8880,

问题是:为什么对ClientSocket bind(port 8880)时,会报错EADDRINUSE?我已经启用了SO_REUSEADDR。

为了方便于大家试运行,我把代码简化的没有其他库依赖,只需g++ -o demo demo.cpp即可运行。


//demo.cpp
#include <stdio.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <linux/tcp.h>

int SockDemo()
{
sockaddr_in in;
memset(&in,'\0',sizeof(in));
in.sin_family=AF_INET;
in.sin_port=htons(8880);
in.sin_addr.s_addr=INADDR_ANY;

int reuse0=1;
int serv=socket(AF_INET, SOCK_STREAM, 0);
if (setsockopt(serv, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse0, sizeof(reuse0))==-1) return errno;
if (bind(serv, (sockaddr*)&in, sizeof(sockaddr)) == -1) return errno;
if (listen(serv, SOMAXCONN)==-1) return errno;

int reuse1=1;
int client=socket(AF_INET, SOCK_STREAM, 0);
if (setsockopt(client, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse1, sizeof(reuse1))==-1) return errno;

if (bind(client, (sockaddr*)&in, sizeof(sockaddr)) == -1) return errno;
//****** 此处为报错 *****:errno=98, Address already in use.

sleep(1);

close(client);
close(serv);
return 0;

}

int main(int argc, char *argv[])
{
int errcode=SockDemo();
printf("errno=%d, %s.\n", errcode, strerror(errcode));
return 0;
}
...全文
3525 点赞 收藏 20
写回复
20 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
骑自行车 2012-07-27
[Quote=引用 19 楼 的回复:]
客户端bind 干啥 。不是 udp组播时绑定才有意义??
tcp绑定又不做服务器。。。。。。

17楼的说法
[/Quote]
没法完
17楼介绍学习了
回复
骑自行车 2012-07-27
客户端bind 干啥 。不是 udp组播时绑定才有意义??
tcp绑定又不做服务器。。。。。。

17楼的说法
回复
zhujas 2012-07-13
楼主找到答案了吗?我也不懂这个问题,如果有答案麻烦说一下啊,谢谢
回复
liwooood 2011-06-30
使用 SO_REUSEPORT 这个吧。

SO_REUSEADDR和SO_REUSEPORT
SO_REUSEADDR提供如下四个功能:
SO_REUSEADDR允许启动一个监听服务器并捆绑其众所周知端口,即使以前建立的将此端口用做他们的本地端口的连接仍存在。这通常是重启监听服务器时出现,若不设置此选项,则bind时将出错。
SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。对于TCP,我们根本不可能启动捆绑相同IP地址和相同端口号的多个服务器。
SO_REUSEADDR允许单个进程捆绑同一端口到多个套接口上,只要每个捆绑指定不同的本地IP地址即可。这一般不用于TCP服务器。
SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)。
SO_REUSEPORT选项有如下语义:
此选项允许完全重复捆绑,但仅在想捆绑相同IP地址和端口的套接口都指定了此套接口选项才性。
如果被捆绑的IP地址是一个多播地址,则SO_REUSEADDR和SO_REUSEPORT等效。
使用这两个套接口选项的建议:
在所有TCP服务器中,在调用bind之前设置SO_REUSEADDR套接口选项;
当编写一个同一时刻在同一主机上可运行多次的多播应用程序时,设置SO_REUSEADDR选项,并将本组的多播地址作为本地IP地址捆绑。

#define SO_REUSEPORT 15
回复
proad 2009-01-14
没有满意答案,高手继续……
回复
proad 2009-01-13
[Quote=引用 14 楼 tonywangm 的回复:]
问:SOMAXCONN的值=?
[/Quote]

/usr/include/linux/socket.h:#define SOMAXCONN 128
不过这代码应该和SOMAXCONN没关系吧
回复
tonywangm 2009-01-11
问:SOMAXCONN的值=?
回复
nowplaycn 2009-01-09
可以重复bind,并且已有的socket不受影响。因为ftp的active模式在传输数据时,使用同一个端口连接到不同的客户端。
回复
无知者无谓 2009-01-07
accept得到的就是一个可用的socket了 不需要再bind
只有服务监听端口才需要进行bind操作
回复
proad 2009-01-06
[Quote=引用 10 楼 proad 的回复:]
如果真如各位所说,下面的现象该做何解释??

示例代码中,只要去掉listen(serv, SOMAXCONN)一句即可正常运行。
[/Quote]

另外,如果先执行socket client相关代码,再执行socket serv相关代码,也能成功。
但这不满足我的需要,我需要先准备好socket serv后再操作socket client。
回复
proad 2009-01-06
如果真如各位所说,下面的现象该做何解释??

示例代码中,只要去掉listen(serv, SOMAXCONN)一句即可正常运行。
回复
threeleafzerg007 2009-01-05
详细情况 参见 UNP 166-168
回复
threeleafzerg007 2009-01-05
对于 TCP 不能进行完全重复捆绑 指定SO_REUSEADDR也没用
对于 支持多播系统的 UDP 才可以。
回复
proad 2009-01-04
回楼上:我想应该是这么区分的,从哪个连接(socket)来的数据就属于哪个连接(socket)的,server和client是不同的socket
回复
快乐田伯光 2009-01-04
不可能吧,同一台机器都bind到同一个端口,系统怎么去区分数据到底是给server的还是给client的。

[Quote=引用 5 楼 proad 的回复:]
引用 3 楼 hairetz 的回复:
然后建一个ClientSocket(受限于业务需要,必须在ServerSocket准备好后再建Client),也必须绑定同一端口8880,
实在是诡异,能说说原因不?


这是TCP方式的P2P所需要的。

根据资料上所说,建两个socket(一个server,一个client),都bind到同一端口上。
资料上所说的应该没错吧,希望各位高手继续分析原因。谢谢!
[/Quote]
回复
proad 2009-01-04
[Quote=引用 3 楼 hairetz 的回复:]
然后建一个ClientSocket(受限于业务需要,必须在ServerSocket准备好后再建Client),也必须绑定同一端口8880,
实在是诡异,能说说原因不?
[/Quote]

这是TCP方式的P2P所需要的。

根据资料上所说,建两个socket(一个server,一个client),都bind到同一端口上。
资料上所说的应该没错吧,希望各位高手继续分析原因。谢谢!
回复
Cpp权哥 2009-01-03
SO_REUSEADDR不是在同一台计算机上多个socket可以绑定同一个端口。
一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即就可以被再次使用。
回复
然后建一个ClientSocket(受限于业务需要,必须在ServerSocket准备好后再建Client),也必须绑定同一端口8880,
实在是诡异,能说说原因不?
回复
linaxing 2009-01-03
楼上正解。
为什么要server和client同时绑定同一个端口啊?
一般情况下只需server端绑定即可,client端connect到这个端口。
回复
lwzlemon 2009-01-03
可能是你对SO_REUSEADDR误解了。
SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,才可以重复绑定使用。
回复
发动态
发帖子
Linux/Unix社区
创建于2007-08-27

2.0w+

社区成员

Linux/Unix社区 应用程序开发区
申请成为版主
社区公告
暂无公告