TCP套接字端口复用SO_REUSEADDR

下面创建的套接字都是tcp套接字编程


1.进程建立监听套接字socket1,邦定一个指定端口,并接受了若干链接。那么进程建立另一个套接口socket2,并试图邦定同一个端口时候,bind错误返回“Address already in use”(即便使用了SO_REUSEADDR).

2.进程建立监听套接字,邦定一个指定端口,并接受了若干链接,为每一个链接建立子进程为链接服务。杀死监听套接字所在进程,而后从新启动。从新启动的进程调用bind从新创建监听套接字。此次邦定只有在bind前指定了SO_REUSEADDR时才能成功。(由于直接杀进程,没有显式关闭套接字来释放端口,会等待一段时间后才能够从新use这个关口,解决办法就是用SO_REUSEADDR)。

3.进程建立套接字socket1,邦定一个指定端口,使用这个套接字去connect另一个监听套接字。链接创建。而后进程创建一个监听套接字socket2,邦定同一个端口。此次邦定只有在下面两个条件都知足的状况下才成功返回:为socket2邦定前指定SO_REUSEADDR,且为socket1邦定前也指定了SO_REUSEADDR。

4.进程建立套接字socket1,邦定一个指定端口,去链接某个监听套接口。杀死进程,保证socket1一端执行主动关闭。那么重启进程后,除非上一个链接中socket1退出了TIME_WAIT状态,不然重启的进程在调用bind时候错误返回。
服务器

 

同一个机器上一个端口PORT1,TCP socket1 绑定PORT1,而后TCP socket2绑定PORT1会失败;网络

同一个机器上一个端口PORT1,TCP socket1 绑定PORT1,而后UDP socket2绑定PORT1会成功;socket

同一个机器上一个端口PORT1,UDP socket1 绑定PORT1,而后UDP socket2绑定PORT1会失败;tcp

 

同一个机器上一个端口PORT1,TCP socket1 绑定PORT1,而后TCP socket2绑定PORT1会成功的条件是:测试

两个套接字绑定前都调用:spa

int opt = 1;  server

// sockfd为须要端口复用的套接字  blog

setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const voidvoid *)&opt, sizeof(opt));接口

可是假如socket1不只bind了,还listen,而且accept成功了,这个时候socket2再次绑定到这个端口就会失败!!可是假如socket2是UDP的socket,那么socket2的bind仍是会成功的!!!

 

端口复用容许在一个应用程序能够把 n 个套接字绑在一个端口上而不出错。同时,这 n 个套接字发送信息都正常,没有问题。可是,这些套接字并非全部都能读取信息,只有最后一个套接字会正常接收数据。

端口复用最经常使用的用途应该是防止服务器重启时以前绑定的端口还未释放或者程序忽然退出而系统没有释放端口。这种状况下若是设定了端口复用,则新启动的服务器进程能够直接绑定端口。若是没有设定端口复用,绑定会失败,提示ADDR已经在使用中——那只好等等再重试了,麻烦!

 

复用真正是什么意义呢?这个咱们能够看看TCP/IP里面TCP创建和断开连接的方法。

咱们知道,在TCP断开连接的时候咱们须要四次握手来断开,并且当两端都关闭了read/write通道之后咱们仍是要等待一个TIME_WAIT时间。

这就是SO_REUSEADDR的做用所在.

其实这个选项就是告诉OS若是一个端口处于TIME_WAIT状态, 那么咱们就不用等待直接进入使用模式, 不须要继续等待这个时间结束.

那这样咱们确定要问,那为何咱们须要有这个TIME_WAIT时间啊?

看看TCP/IP协议组咱们就知道,这样作是为了让在网络中残余的TCP包消失, 也就是说, 若是咱们没有等到这个时间就让OS把这个端口释放给其余的进程使用,别的进程颇有可能就会收到上一个会话的残余TCP包,这样就会出现一系列的不可预知的错误.

1、保证TCP协议的全双工链接可以可靠关闭
2、保证此次链接的重复数据段从网络中消失

那么何时咱们能够用这个选项以加快咱们进程的速度减少等待时间呢?

这里有一些例子:

SO_REUSEADDR能够用在如下四种状况下。
(摘自《Unix网络编程》卷一,即UNPv1)
一、当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你启
动的程序的socket2要占用该地址和端口,你的程序就要用到该选项。
二、SO_REUSEADDR容许同一port上启动同一服务器的多个实例(多个进程)。但
每一个实例绑定的IP地址是不能相同的。在有多块网卡或用IP Alias技术的机器可
以测试这种状况。
三、SO_REUSEADDR容许单个进程绑定相同的端口到多个socket上,但每一个soc
ket绑定的ip地址不一样。这和2很类似,区别请看UNPv1。
四、SO_REUSEADDR容许彻底相同的地址和端口的重复绑定。但这只用于UDP的
多播,不用于TCP。

也就是说,不是全部的状况咱们均可以使用这个选项的,请参阅这篇淘宝的案例:

http://rdc.taobao.com/blog/cs/?p=1195

 

一、通常来讲,一个端口释放后会等待两分钟以后才能再被使用,SO_REUSEADDR是让端口释放后当即就能够被再次使用。

    SO_REUSEADDR用于对TCP套接字处于TIME_WAIT状态下的socket,才能够重复绑定使用。server程序老是应该在调用bind()以前设置SO_REUSEADDR套接字选项。TCP,先调用close()的一方会进入TIME_WAIT状态

二、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地址捆绑。

    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,

   (const void *)&nOptval , sizeof(int)) < 0) ...

    Q:编写 TCP/SOCK_STREAM 服务程序时,SO_REUSEADDR到底什么意思?

    A:这个套接字选项通知内核,若是端口忙,但TCP状态位于 TIME_WAIT ,能够重用端口。若是端口忙,而TCP状态位于其余状态,重用端口时依旧获得一个错误信息,指明"地址已经使用中"。若是你的服务程序中止后想当即重启,而新套接字依旧使用同一端口,此时SO_REUSEADDR 选项很是有用。必须意识到,此时任何非指望数据到达,均可能致使服务程序反应混乱,不过这只是一种可能,事实上很不可能。

    一个套接字由相关五元组构成,协议、本地地址、本地端口、远程地址、远程端口。SO_REUSEADDR 仅仅表示能够重用本地本地地址、本地端口,整个相关五元组仍是惟一肯定的。因此,重启后的服务程序有可能收到非指望数据。必须慎重使用SO_REUSEADDR 选项。【2】

相关文章
相关标签/搜索