Shutdown的调用
#include<sys/socket.h>
#include<winsock.h>
int shutdown(SOCKET s,inthow)
how
|
操作
| ||
数字
|
POSIX
|
Winsock
| |
0
|
SHUT_RD
|
SD_RECEIVE
|
关闭连接接收方
|
1
|
SHUT_WR
|
SD_SEND
|
关闭连接的发送方
|
2
|
SHUT_RDWR
|
SD_BOTH
|
关闭双方
|
说明
:
1. shutdown根本没有关闭socket,任何与socket关联的资源直到调用closesocket才释放。
2. TCP连接的socket是全双工的,也就是说它可以发送和接收数据,但是一个方向上的数据流动和另一个方向上的数据流动是不相关的,shutdown函数的功能也就是体现在这里,它通过设置how选择关闭哪条数据通道(发送通道和接收通道),如果关闭了发送通道,那么这个socket其实还可以通过接收通道接受数据.
3. 当通过以how=1的方式调用shutdown,就可以保证对方收到一个EOF,而不管其他的进程是否已经打开了套接字,而调用close或closesocket就不能保证,因为直到套接字的引用计数减为0时才会发送FIN消息给对方,也就是说,直到所有的进程都关闭了套接字。
例子说明
1. shutdown关闭发送数据通道后,通过抓包程序获取的tcp处理过程。
![TCP顺序释放操作和tcp的半关闭](https://p-blog.csdn.net/images/p_blog_csdn_net/lllxy/46d6dfb6a22e485682ae977dbdae1dbc.png)
对上面的处理过程进行分析:
l 前面的三条记录是tcp的三次握手.
l 第四条记录就是客户端第一次向服务器发送数据
l 第五条记录是服务器的确认信息
l 第六条记录就是客户端间隔2秒后第二次向服务器发送数据
l 第七条记录时服务器的确认信息
l 第八条记录是在等待2秒后,调用了shutdown,客户端向服务器发送了FIN标志
l 第九条记录时服务器的确认信息
l 第十条记录是服务器接收到客户端的一条记录后休眠4秒,发回给客户端
l 第十一条记录是客户端的确认
l 第十二条记录是服务器接受到客户端的第二条数据后休眠4秒,发回给客户端
l 第十三条记录是客户端的确认
l 第十四条记录是服务器发送完tcp对列中的数据后,向客户端发送FIN标志
l 第十五条记录时客户端对FIN标志的确认
2. closesocket关闭socket,通过抓包程序获取的tcp处理过程
![TCP顺序释放操作和tcp的半关闭](https://p-blog.csdn.net/images/p_blog_csdn_net/lllxy/542945c4158d4aa1824c7aa3ee36a5b6.png)
Closesocket关闭socket时,tcp的状态处理过程
对上面的处理过程进行分析:
l 前面的三条记录是tcp的三次握手.
l 第四条记录就是客户端第一次向服务器发送数据
l 第五条记录是服务器的确认信息
l 第六条记录就是客户端间隔2秒后第二次向服务器发送数据
l 第七条记录时服务器的确认信息
l 第八条记录是在等待2秒后,调用了shutdown,客户端向服务器发送了FIN标志
l 第九条记录时服务器的确认信息
l 第十条记录是服务器接收到客户端的一条记录后休眠4秒,发回给客户端
l 第十一条记录是由于客户端已经通过closesocket关闭了连接,连接已经不存在,因此客户端向服务器发送了RST标志
总结
单工就相当于二极管,数据只能从一端流向另一端。全双工就相当于一个完整的电路,数据可以从A流到B,也可以从B流动会到A,他们甚至还可以同时进行。 在计算机连接的另一端发送FIN包时socket不会自动发送FIN包。它为被标识为不可读但可写的状态。 把socket标识为可写不可读的状态就意味着它并没有断开,只是认为对方告诉自己将不再发送数据了而已。如果是Socket程序,就需要手动调用方法去关闭这个连接,否则它会一直工作。有些恶意攻击的程序就利用这个机制让没有限制半开连接的服务器打开大量的半开连接,使对方的连接数消耗殆尽。所以很多操作系统都自带了半开连接数的使用限制。