今天在看网络的书,自己想写一个TCP连接半关闭的程序.在连接建立之后,客户端调用了close函数,但是服务器端并没有close.端口的状态和书上讲的一样,客户端进入过了FIN_WAIT2状态,而服务器端进入了CLOSE_WAIT状态.但是客户端在继续向客户端写入数据时,写入成功,但是客户端读取出了错误.网上一查,发现时close函数调用的不对.
先说一下close和shutdown两个函数的作用.
close函数首先将socket fd的reference减一,若reference依旧大于0,则该socket端口的状态保持不变;若reference等于0,则首先将sender buffer中的数据全部发送出去,并将receive buffer中的数据全部丢弃,最后发送FIN,执行主动关闭。这里的关闭时将读写两个方向的数据传输全部关闭,所以在调用close之后并不能从中读取到数据.
而shutdown函数禁止了这个套接字的数据发送,并且发送发送FIN报文.特别说明的是:shutdown函数并不会去关闭fd,这个函数不会对fd进行操作
下面摘抄一下unix网络编程的叙述:
shutdown(SHUT_RD):在套接口上不能再发出接受请求;进程仍可往套接口发送数据;套接口接受缓冲区中所有数据被丢弃;再接收到的数据被TCP丢弃,对套接口发送缓冲区无影响.
shutdown(SHUT_WR)在套接口上不能在发出发送请求;进程仍可以从套接口接受数据;套接口发送缓冲区的内容被发送到对端,后跟正常的TCP连接终止序列(发送FIN);对套接口接收缓冲区无任何影响.
close(l_onoff=0缺省状态):在套接口上不能在发出发送或接收请求;套接口发送缓冲区中的内容被发送到对端.如果描述字引用计数变为0;在发送完发送缓冲区中的数据后,跟以正常的TCP连接终止序列(发送FIN);套接口接受缓冲区中内容被丢弃
close(l_onoff = 1, l_linger =0):在套接口上不能再发出发送或接受请求,如果描述子引用计数变为0,RST被发送到对端;连接的状态被置为CLOSED(没有TIME_WAIT状态),套接口发送缓冲区和套接口接受缓冲区的数据被丢弃
close(l_onoff =1, l_linger != 0):在套接口上不能在发出发送或接收请求;套接口发送缓冲区中的内容被发送到对端.如果描述字引用计数变为0;在发送完发送缓冲区中的数据后,跟以正常的TCP连接终止序列(发送FIN);套接口接受缓冲区中内容被丢弃;如果在连接变成CLOSED状态前延滞时间到,那么close返回EWOULDBLOCK错误.
上面描述了何时只是关闭读写,何时要发送FIN报文终止连接,此外自己在写代码验证的过程中,发现了一个小问题
在使用close和shutdown函数时,客户端状态进入FIN_WAIT2状态,而服务器端进入了CLOSE_WAIT状态.但是当使用close函数时,超过一定的时间,客户端会自动关闭套接字,而shutdown函数不会.上网查找的原因时,这个是一般操作系统的实现,但是在TCP协议中没有这个超时时间.设置超时的原因时,防止客户端一直不释放连接,当服务器主动关闭时,不能回收fd资源,导致服务器崩溃.所以当使用close函数关闭套接字时,当状态进入FIN_WAIT2时,超过一定的时间,会自动关闭套接字.