和同事的联调时碰到一个诡异的问题,server端的业务逻辑层面没有任何异常,但返回结果给client端时,并没有发送完所有的数据,就直接发送了RST给client,导致client读取结果失败。注: client与server直接是短连接,server在write所有的数据后会直接close。
通过tcpdump截包对比之前旧版本正常的client端通信,发送server与旧版本的client通信时,三次握手 => client发送数据 => server发送响应数据 => 四次挥手。但与新版本client通信时,则直接是 三次握手 => client发送数据 => server发送响应数据(未完成) => server发送RST。
借助强大的Google大神,以及万能Stackoverflow。原因如下:当close断开连接时,如果缓冲区中又未被读取的数据,则tcp不会发送正常的FIN包,而发送RST给对端。
简单测试一下,代码如下,client和server的主要代码如下:
/*
*client
*/
voidsend_plain_buf(intfd,size_tbuf_size)
{
charbuf[buf_size];
memset(buf,0,buf_size);
intret=write(fd,buf,buf_size);
if(ret<0){
fprintf(stderr,"sendfailed,err[%m]\n");
return;
}
ret=read(fd,buf,1);
if(ret==0){
fprintf(stderr,"clientgetFIN\n");
}else{
fprintf(stderr,"readret[%d],err[%m]",ret);
}
return;
}
/*
*server
*/
voidrecv_plain_buf(intfd,size_tbuf_size)
{
charbuf[buf_size];
memset(buf,0,buf_size);
intret=read(fd,buf,buf_size);
if(ret<0){
fprintf(stderr,"serverrecvfailed,err[%m]\n");
return;
}
return;
}
测试一:client发送1个byte,server读取1个byte,tcpdump截包
21:35:43.829700IPtc-im-nrd306..22579>tc-im-nrd301..8654:S3630522968:3630522968(0)win5840<mss1460,sackOK,timestamp18273110720,nop,wscale7>
21:35:43.829706IPtc-im-nrd301..8654>tc-im-nrd306..22579:S2472593503:2472593503(0)ack3630522969win5792<mss1460,sackOK,timestamp24296503781827311072,nop,wscale7>
21:35:43.829846IPtc-im-nrd306..22579>tc-im-nrd301..8654:.ack1win46<nop,nop,timestamp18273110732429650378>
21:35:43.829873IPtc-im-nrd306..22579>tc-im-nrd301..8654:P1:2(1)ack1win46<nop,nop,timestamp18273110732429650378>
21:35:43.829876IPtc-im-nrd301..8654>tc-im-nrd306..22579:.ack2win46<nop,nop,timestamp24296503781827311073>
21:35:43.829888IPtc-im-nrd301..8654>tc-im-nrd306..22579:F1:1(0)ack2win46<nop,nop,timestamp24296503781827311073>
21:35:43.830035IPtc-im-nrd306..22579>tc-im-nrd301..8654:.ack2win46<nop,nop,timestamp18273110732429650378>
21:35:43.830080IPtc-im-nrd306..22579>tc-im-nrd301..8654:F2:2(0)ack2win46<nop,nop,timestamp18273110732429650378>
21:35:43.830083IPtc-im-nrd301..8654>tc-im-nrd306..22579:.ack3win46<nop,nop,timestamp24296503781827311073>
测试二:client发送2个byte,server读取1个byte,tcpdump截包
21:36:31.137496IPtc-im-nrd306..22580>tc-im-nrd301..8654:S3686863514:3686863514(0)win5840<mss1460,sackOK,timestamp18273583880,nop,wscale7>
21:36:31.137501IPtc-im-nrd301..8654>tc-im-nrd306..22580:S2526723815:2526723815(0)ack3686863515win5792<mss1460,sackOK,timestamp24296976931827358388,nop,wscale7>
21:36:31.137666IPtc-im-nrd306..22580>tc-im-nrd301..8654:.ack1win46<nop,nop,timestamp18273583882429697693>
21:36:31.137671IPtc-im-nrd306..22580>tc-im-nrd301..8654:P1:3(2)ack1win46<nop,nop,timestamp18273583882429697693>
21:36:31.137676IPtc-im-nrd301..8654>tc-im-nrd306..22580:.ack3win46<nop,nop,timestamp24296976931827358388>
21:36:31.137705IPtc-im-nrd301..8654>tc-im-nrd306..22580:R1:1(0)ack3win46<nop,nop,timestamp24296976931827358388>
在net/ipv4/tcp.c:1900行附近的代码如下:
/*AsoutlinedinRFC2525,section2.17,wesendaRSTherebecause
*datawaslost.Towitnesstheawfuleffectsoftheoldbehaviorof
*alwaysdoingaFIN,runanolder2.1.xkernelor2.0.x,startabulk
*GETinanFTPclient,suspendtheprocess,waitfortheclientto
*advertiseazerowindow,thenkill-9theFTPclient,wheee...
*Note:timeoutisalwayszeroinsuchacase.
*/
if(data_was_unread){
/*Unreaddatawastossed,zaptheconnection.*/
NET_INC_STATS_USER(sock_net(sk),LINUX_MIB_TCPABORTONCLOSE);
tcp_set_state(sk,TCP_CLOSE);
tcp_send_active_reset(sk,sk->sk_allocation);
..
标签:TCP
顶一下
(49385)
100.00%
踩一下
(16)
0.00%