TCP的“非”可靠性
Posted 为了维护世界和平_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TCP的“非”可靠性相关的知识,希望对你有一定的参考价值。
目录
应用层调用send函数后,数据被转发到内核的发送缓冲区中,由协议栈决定什么时候发。当数据发送给对端,对端会反馈ACK,本端的发送套接字缓冲区的相应数据可以删除。
如果发送端没有获取到ACK,不知道对端有没有接收到数据。这种情况怎么处理呢?在应用层增加处理逻辑。
从接收端角度,没有办法保证ACK过的数据可以被应用程序处理。因为数据需要从接收套接字缓冲区拷贝到应用层。如果数据已经存储在接收端的套接字缓冲区中,如果程序被崩溃,这部分数据就丢失了。
数据建立连接后,一种通过read操作,一种是write操作,这个两个操作可以感知异常情况。
网络中断造成对端无FIN包
操作 read
如果采用阻塞读操作,程序无法恢复。 解决方法,read操作设置超时
操作 write
先发送了一段数据流,接下来阻塞在read上。TCP协议栈会不断尝试将发送缓冲区的数据发送出去,再多次失败后,阻塞read上的操作会反馈TIMEOUT的错误信息。
如果此时程序执着地往这条链路上写数据,写操作会失败,并返回SIGPIPE信号给应用程序。
系统崩溃造成对端无FIN包
如系统崩溃,没来得及发送FIN包。崩溃后系统重启,当重传的TCP分组到达重启的系统后,由于系统中没有该TCP分组对应的连接数据,系统会返回RST。
操作 read
如果是阻塞的read调用,会立即反馈一个错误(Connection Reset)
操作 write
如果是write操作,会立即失败,应用程序反馈SIGPIPE信号。
对端有FIN包
可能调用close或shutdown,
可能是对端程序崩溃,操作系统内核代为清理所发出,阻塞的read操作在完成正常结束数据后,FIN包会通过返回EOF,这是内核做的事情。如果应用层不调用read,write 是无法感知的。
通过write产生RST,read调用感知RST
read的返回值为0
向一个已经关闭的连接写,最终导致SIGPIPE
服务器程序被杀死,操作系统会为这个套接字发送FIN包。客户端在收到FIN包后,没有read操作,会继续往这个套接字写入数据。TCP协议,连接是双向的,收到对方的FIN包意味着对方不会再发送任何数据。当数据到达服务器时,操作系统发现内核已经关闭了套接字,会再向客户端发出RST包。对于发送端而言,如果再写,会立即返回一个RST信息。
验证数据有效性
1)read、write调用返回值判断
通过判断EOF,防范程序崩溃。如果服务端同时处理多个客户连接,一般调用shutdown关闭连接的一端
2)设置read超时操作
struct timeval tv;
tv.tv_sec=2;
tv.tv_usec = 0;
setsockopt(connfd,SOL_SOCKET,SO_RECVTIMEO,(const char *)&tv,sizeof tv);
while(1)
int n=recv(connfd,buffer,sizeof(buffer),0);
...
3)超时处理
for (;;)
readmask = allreads;
int rc = select(socket_fd + 1, &readmask, NULL, NULL, &tv);
if (rc < 0)
error(1, errno, "select failed");
if (rc == 0)
printf("read timeout\\n");
...
...
select返回0 是超时
4)缓冲区处理
接收数据的缓冲区要能容纳的下所接收的数据
发送的数据内容与内容长度匹配,如果数据长度过长,接收端阻塞,等待数据到来。
减少多次系统调用的开销,举例如下:
//验证收数据的特定字符,先用recv读取多个数据,再依次验证,而不是读一次验证一次
size_t readline(int fd, char *buffer, size_t length)
while (--length> 0)
if (nleft <= 0)
//一次读取过个
int nread = recv(fd, read_buffer, sizeof(read_buffer), 0);
//异常处理
if (nread < 0)
if (nread == 0)
return 0;
buffer_pointer = read_buffer;
c = *buffer_pointer++;
//验证数据
if (c == '\\n')
*buffer = '\\0';
//反馈读取的数据
return buffer - buf_first;
return -1;
参考
https://course.0voice.com/v1/course/intro?courseId=2&agentId=0
开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系
以上是关于TCP的“非”可靠性的主要内容,如果未能解决你的问题,请参考以下文章