1、出现 情形:
使用ctrl+c终止程序:
(1)终止client.c ----->终止server.c ------>启动server.c -----> 启动client.c 不会出现问题(客户端主动断开连接情况)
(2)终止server.c ----->终止client.c ------>启动server.c ----->启动client.c 会出现问题(服务器主动断开连接的情况)
使用 netstat -apn|grep 端口号 查看端口号的占用情况
2、原因:
先终止server.c的时候,端口号没有被释放。当再启动server.c的时候,就会报错端口被占用,错误信息如下:
bind函数会报错,Address already in use
进一步分析,这是由于服务器端先关闭的话,服务器会处于2MSL时长的TIME_WAIT状态(程序终止了,但是TCP协议层的连接没有完全断开),端口仍然在占用,故会报该错误。
先关闭客户端程序则不会出现这种问题,则是因为,虽然客户端先关闭后,客户端也会处于2MSL时长的TIME_WAIT状态,客户端的端口也会被占用,但是,因为客户端程序中并没有调用bind函数,即客户端的绑定的端口号是系统随机分配的,当再次启动客户端时,客户端又会被重新分配新的端口号,不会出现端口被占用的情况。
当先终止server.c后,查看网络连接状态,发现,服务器端的状态是FIN_WAIT2.,客户端的状态是CLOSE_WAIT
等待一会后,发现服务器端消失了,只剩下客户端的状态了。
这是因为,server.c终止,会发送FIN给client.c,client发送ACK给server.c后,自身变为CLOSE_WAIT,而服务器端变为FIN_WAIT2. 客户端此时并没有关闭,不会向server.c发送FIN,状态也不会改变。
我们在先关闭服务器程序后,想立即重启服务器程序,不希望等待2MSL时长,那如何解决这个问题呢?这就用到了端口复用
3、端口复用
使用setsockopt()函数对socket进行端口复用。
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
int opt=1;
setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(opt);
将SO_REUSEADDR的值赋值为1,则表示生效,赋值为0,则无效。
放在socket函数之后,bind函数之前。
此时终止server.c后,再重启server.c,网络状态仍然为TIME_WAIT,但是不会报错,程序能够正常运行。