程序设计中的问题
首先我们做一个测试,先启动server,然后启动client,用Ctrl+c终止server,在马上运行server,会导致出错,如下:(错误提示在代码中定义)
这是由于,虽然server的应用程序终止了,但是TCP协议层的连接还未完全断开,因此不能马上监听同样的server端口,我们可以用netstat -apn|greap 6666查看一下端口号为6666的状态:
server终止时,socket描述符会自动关闭并发FIN段给client,client收到FIN后处于CLOSE_WAIT状态,但是client并未终止,也没有关闭socket描述符,因此不会发FIN给server,因此server的TCP连接处于FIN_WAIT2状态。
现在将client也使用Ctrl+c终止,在观察:
client终止时自动关闭socket描述符,server的TCP连接收到client发的FIN段后处于TIME_WAIT状态。TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL的时间后才可以回到CLOSED状态,因为我们先终止了server,所以server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口。
MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同,在linux上一般是半分钟就可再次启动server了。
端口复用
在server的TCP连接没有完全断开之前不允许重新监听是不合理的,因为TCP连接没有完全断开是指connfd(127.0.0.0:6666)没有完全断开,而我们重新监听放入是listenfd(0.0.0.0:6666),虽然是占用同一个端口,但是IP地址不同,connfd对应的是与某个客户端通讯的一个具体的IP地址,而listenfd对应的是wildcard address,解决这个问题的方法是使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1,表示允许创建端口号相同但IP不同的多个socket描述符。使用方法如下:
在server代码的socket()和bind()调用之间插入如下代码:
有关setsockopt可以设置的其他选项在UNP第七章!