现象为客户端连接服务端,服务端日志返回写socket成功,但是客户端报错“read socket error”
把能调的超时时间都调大了,但是还是报错
抓包结果服务端:
抓包结果客户端:
分析原因:
1、可以看到客户端是发送完请求后,收到rst指令,导致连接断开
客户端添加日志打印errno
{
while((num=read(nsockfd,&buf[iReadlen],len-iReadlen))<0){
HtLog (gsLogFile, HT_LOG_MODE_NORMAL, __FILE__,__LINE__, "read socket num[%d]", num);
if (errno == EINTR) continue;
HtLog (gsLogFile, HT_LOG_MODE_ERROR, __FILE__,__LINE__, "read socket error");
HtLog (gsLogFile, HT_LOG_MODE_NORMAL, __FILE__,__LINE__, "errno[%d]", errno);
alarm(0);
return -1;
}
if(num == 0){
alarm(0);
return 0;
}
HtLog (gsLogFile, HT_LOG_MODE_NORMAL, __FILE__,__LINE__, "num[%d]", num); /*[*1*] modify ERROR -> NORMAL*/
iReadlen+=num;
if(iReadlen>=len) break;
if( vnRdFlg ) break;
}
结果为104:
errno: 104 Connection reset by peer
2、经过排查代码
int Setsokopt(int sdNew)
{
struct linger soLinger;
int soKeepAlive,soReuseAddr;
/*************************************************/
/* Set socket options for new socket */
/*************************************************/
soLinger.l_onoff = 1;
soLinger.l_linger = 0;
if( -1 == setsockopt(sdNew,
SOL_SOCKET,
SO_LINGER,
(char*)&soLinger,
sizeof(soLinger)))
{
HtLog (gsLogFile, HT_LOG_MODE_ERROR, __FILE__,__LINE__,
"set linger option failed!");
return -1;
}
soKeepAlive = 0;
if( -1 == setsockopt(sdNew,
SOL_SOCKET,
SO_KEEPALIVE,
&soKeepAlive,
(int)sizeof(soKeepAlive)))
{
HtLog (gsLogFile, HT_LOG_MODE_ERROR, __FILE__,__LINE__,
"set keepalive option failed!");
return -1;
}
soReuseAddr = 1;
if( -1 == setsockopt(sdNew,
SOL_SOCKET,
SO_REUSEADDR,
&soReuseAddr,
(int)sizeof(soReuseAddr)))
{
HtLog (gsLogFile, HT_LOG_MODE_ERROR, __FILE__,__LINE__,
"set reuse addr option failed!");
return -1;
}
return 0;
}
代码中设置了linger,并且soLinger.l_linger = 0;
3、查询得知“在设置SO_LINGER选项时,指定等待时间为0,此时调用主动关闭时不会发送FIN来结束连接,而是直接将连接设置为CLOSE状态,清除套接字中的发送和接收缓冲区,直接对对端发送RST包。”
4、将l_linger改为1就可以了
5、正常TCP握手是返回FIN,但是由于设置了soLinger,返回了RST。和网络延迟有关系,就是说服务端发了两个包,一个是数据包,一个是RST包,但是客户端总是先收到RST包导致接收数据失败
6、参考资料:
https://www.cnblogs.com/jingzhishen/p/5543627.html
https://www.cnblogs.com/Jimmy1988/p/7485133.html