端口重用和端口独占程序的设计
作者: alexclark(http://alexclark.itpub.net)发表于: 2005.11.04 10:48
分类: 沧海一粒
出处: http://alexclark.itpub.net/post/670/44817
---------------------------------------------------------------
前段时间,一个朋友发来邮件,说在RedHat Linux 9.0
操作系统的机器上,编写了一个服务程序。该服务程序用Ctrl+C终止后,不能够马上重新运行。出现地址绑定错误,也就是调用bind()函数时,出现错
误。但过了几分钟后,即可以正常运行。不明白原因,并希望能给于解决。
首先,来了解出现这个问题的原因。如果出现上面的情况,可以用netstat -an
命令查看一下,就会发现那个服务程序所使用的端口处在CLOSE_WAIT状态。当程序执行主动关闭的时候,就会进入这种状态。还有一种情况,就是客户端
还在保持连接,但服务器却意外终止,这种情况,也会有这种状态产生,特别是在一些老的UNIX操作系统中,非常常见。例如SCO系统。那么这种状态要保持
多长时间呢?这种状态的端点留在该状态的持续时间是最长数据分组的生命周期MSL (Maximum Segment
Lifetime)的两倍,也称为2MSL。因此,在这段时间内,程序是无法使用这个端口的,因为这个端口资源还没有完全释放。
对于每个TCP
连接实现,都必须选择一个MSL值。在RFC1122文档中建议这个值是2分钟。而源自的Berkeley的实现传统上MSL这个值为30秒。这就意味着
TIME_WAIT状态可能保持1分钟到4分钟之间。而在这段时间内,使用这个端口就可能要到前面所说的那种障碍。
问题产生的原因知道了,那么如何解决呢?套接字的选项中有一个SO_REUSEADDR选项,就可以解决这个问题。SO_REUSEADDR选项允许完全重复的绑定。这个选项通过setsockopt()来进行设置。先来看一下这个函数的定义格式:
#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int s, int level, int optname, const void *optval,
socklen_t optlen);
s: 套接字,指向一个打开的套接口描述字
level:级别,指定选项代码的类型。具体类型如下:
SOL_SOCKET: 基本套接口
IPPROTO_IP: IPv4套接口
IPPROTO_IPV6: IPv6套接口
IPPROTO_TCP: TCP套接口
optname:选项名,选项名称
optval: 选项值,是一个指向变量的指针类型
optlen :选项长度,即 optval 的大小
返回值:如果函数执行成功,返回0;如果函数执行失败,返回-1。
因此,可以按照下面的伪代码来实现:
int sockfd;
int cflag;
sockfd =socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sockfd < 0)
{
printf("socket() errorn");
exit(-);
}
cflag = 1;
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,
(char *)&cflag,sizeof(cflag)) == -1)
{
printf("setsockopt() errorn");
exit(-);
}



