为什么正确的关闭TCP连接
来源:互联网 发布:什么叫大数据金融 编辑:程序博客网 时间:2024/05/17 22:10
收到的数据不完整,
先看一个例子,如下
#include "Acceptor.h"#include "InetAddress.h"#include "TcpStream.h"#include <thread>#include <unistd.h>void sender(const char* filename, TcpStreamPtr stream){ FILE* fp = fopen(filename, "rb"); if (!fp) return; printf("Sleeping 10 seconds.\n"); //让我们有机会从另一端输入数据 sleep(10); printf("Start sending file %s\n", filename); char buf[8192]; size_t nr = 0; while ( (nr = fread(buf, 1, sizeof buf, fp)) > 0) { stream->sendAll(buf, nr); } fclose(fp); printf("Finish sending file %s\n", filename); // Safe close connection,可先注释掉,复现出发数据不完整的情况 /* printf("Shutdown write and read until EOF\n"); stream->shutdownWrite(); while ( (nr = stream->receiveSome(buf, sizeof buf)) > 0) { // do nothing } printf("All done.\n");*/ // TcpStream destructs here, close the TCP socket.}int main(int argc, char* argv[]){ if (argc < 3) { printf("Usage:\n %s filename port\n", argv[0]); return 0; } int port = atoi(argv[2]); Acceptor acceptor((InetAddress(port))); printf("Accepting... Ctrl-C to exit\n"); int count = 0; while (true) { TcpStreamPtr tcpStream = acceptor.accept(); printf("accepted no. %d client\n", ++count); std::thread thr(sender, argv[1], std::move(tcpStream)); thr.detach(); }}
此程序再port端口监听,并发送一个文件,f发送下面文件
[root@localhost tpc]# ll ttcp-rwxr-xr-x. 1 root root 1236464 May 6 17:40 ttcp
试验1
[root@localhost tpc]# ./sender ttcp 1234Accepting... Ctrl-C to exitaccepted no. 1 clientSleeping 10 seconds.Start sending file ttcpFinish sending file ttcpAll done.[root@localhost ~]# nc localhost 1234 | wc -c 1236464
可以看出能够完整收到数据
试验2,在nc命令行下输入一点数据
[root@localhost tpc]# ./sender ttcp 1234Accepting... Ctrl-C to exitaccepted no. 1 clientSleeping 10 seconds.Start sending file ttcpFinish sending file ttcpAll done.[root@localhost ~]# nc localhost 1234 | wc -c nishighdsNcat: Connection reset by peer.581156
可以看出收到的数据小了,
注意
如果协议栈的接受缓冲区还有数据,你没有去读,直接close,那么就会导致TCP协议栈发送RST分节,强行的断开连接;如果这时协议栈的发送缓冲区还有数据,对方没收到,那么数据就丢失了,close太早,SO_LINGER此选项无助解决此问题。
正确的做法
sender:shudown(write),对方read返回0,这样的话没有数据send,就会close.反过来导致sender的read返回0.
总结起来read返回0才去close。read返回0表示遇到EOF,此时close是安全的。
这里需要注意是read返回0,才会close关闭连接,如果遇到恶心的客户端,不close,则read会阻塞;因此可能需要加一个超时控制,如果在shutdown()之后若干秒后还没有read返回0,需要自己去close连接。
上面的办法是根据shutdown(write),read返回0判断数据有没有读完,更好办法设计协议的时候把长度包含进去。这样接收方能主动判断数据是否收完毕,收完就可以断开连接。
因为Netcat是无格式的协议,所以需要这种比较绕的方法,
正确关闭TCP连接,
发送完后,关闭写端,一直read直到返回0(EOF).表明对方已经关闭连接;这时调用close,这样一来逻辑就正确了;对于接收方比较简单,read返回0就可以了。read返回0才去close, read返回0表明遇到了EOF,这时候clsoe是安全的。一个因果关系。
总结 陈硕老师的课程。
然后分享一个陈硕老师的链接
https://www.zhihu.com/question/25016042/answer/29798924
TCP是个可靠协议,为什么常见的还要在应用层加个ACK响应?
答:TCP协议栈的ACK表现对方协议栈已经收到了你的数据,但是并不代表对方应用程序已经处理了你的数据,对方可能已经阻塞了或者死锁了,那么数据还是保存在接受缓冲区里,会给你一个TCP的ACK。应用层看不见这个ACK,所以需要加一个TCP的ACK。
- 为什么正确的关闭TCP连接
- 为什么 muduo 的 shutdown() 没有直接关闭 TCP 连接?
- 为什么 muduo 的 shutdown() 没有直接关闭 TCP 连接?
- 主动关闭TCP连接的一方为什么要有TIME_WAIT状态
- TCP连接的关闭
- TCP连接的关闭
- TCP的连接和关闭
- 关闭TCP连接的学问
- TCP的连接和关闭
- 关闭TCP连接的学问
- TCP的连接和关闭
- 关闭TCP连接的学问
- 关闭TCP连接的学问
- 关闭TCP连接的学问
- 关闭TCP连接的学问
- TCP连接的关闭过程
- 关闭TCP连接的学问
- tcp的连接与关闭
- Python 3基础教程17-提问频率较高的几个Python问题
- oracle游标使用
- 存储系统的块关联挖掘C-Miner算法
- Eclipse中采用本地作业运行器(Job Runner)运行Hadoop测试(Hadoop2.7.3)
- Python常用开源工具包
- 为什么正确的关闭TCP连接
- 《C语言程序开发范例宝典》-基础
- 二叉树的层序遍历
- 单元测试之道
- WPF问题
- 成员变量、局部变量、静态变量的区别
- IOS 获取网络状态
- linux下使用crontab定时备份mongodb数据
- CF