关闭socket前没有将缓冲区的数据发送完,而是直接关了

关闭socket前没有将缓冲区的数据发送完,而是直接关了

 

 转。

 

问题:见下面的例子,现在发现每次连接发送数据后,都要加taskDelay(10);后,客户端才能收到数据。否则就直接关闭了socket,没有发数据。
int HttpSvr(void)
{
int nServerFd, nConnectionFd,i;
struct sockaddr_in servAddr;
int nMsgNum;
struct linger optVal;
int addrLen = 0;
/*初始web固态页面*/
if(ERROR == InitWebFile())
{
    myLogMsg("Info:ERROR  == InitWebFile\n",0,0,0,0,0,0);
     return ;
}
/*清空ArrHttpSessions*/
       clearHttpSessions();
       optVal.l_onoff = 1;
       optVal.l_linger = 0;
nServerFd = socket(AF_INET, SOCK_STREAM, 0);
if(ERROR == nServerFd)
{
     myLogMsg("Info:ERROR  == nServerFd\n",0,0,0,0,0,0);
     return ;
}
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(HTTP_SERVER_PORT);
addrLen = sizeof(struct sockaddr_in);
if(ERROR  == bind(nServerFd, (struct sockaddr*)&servAddr, sizeof(servAddr)))
{
     myLogMsg("Info:ERROR  == bind\n",0,0,0,0,0,0);
     return ;
}
if(ERROR == listen(nServerFd, 10))
{
     myLogMsg("Info:ERROR  == listen\n",0,0,0,0,0,0);
     return ;
}
while(1)
{
  nConnectionFd = accept(nServerFd, (struct sockaddr*)&ClientAddr, &addrLen);
  if(ERROR  == nConnectionFd)
  {
     continue ;
  }
        if (setsockopt (nConnectionFd, SOL_SOCKET, SO_LINGER, (char*)&optVal,
      sizeof (optVal)) == ERROR)  
  {
         shutdown(nConnectionFd,2);
   close (nConnectionFd);
   continue ;
  }
        hangdleConnection(nConnectionFd);
        shutdown(nConnectionFd,2);
        taskDelay(10);
        close(nConnectionFd);
}

return 0;
}

 

答复:问题的根源在于optVal.l_linger不能设置为0,如果设置为0,表示立即关闭socket,不管缓冲区是否还有数据要发送。另外socket的属性SO_LINGER是必须的。此选项指定函数close对面向连接的协议如何操作(如TCP)。缺省close操作是立即返回,如果有数据残留在socket缓冲区中则系统将试着将这些数据发送给对方。
SO_LINGER选项用来改变此缺省设置。使用如下结构:
struct linger {
     int l_onoff; /* 0 = off, nozero = on */
     int l_linger; /* linger time */
};
有下列三种情况:
l_onoff为0,则该选项关闭,l_linger的值被忽略,等于缺省情况,close立即返回;
l_onoff为非0,l_linger为0,则套接口关闭TCP连接时,TCP将丢弃保留在套接口发送缓冲区中的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,这避免了TIME_WAIT状态;
l_onoff 为非0,l_linger为非0,当套接口关闭时内核将拖延一段时间(由l_linger决定)。如果套接口缓冲区中仍残留数据,进程将处于睡眠状态,直 到(a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)或(b)延迟时间到。此种情况下,应用程序检查close的返回值是非常重要的,如果在数据发送完并被确认前时间到,close将返回EWOULDBLOCK错误且套接口发送缓冲区中的任何数据都丢失。close的成功返回仅告诉我们发送的数据(和FIN)已由对方TCP确认,它并不能告诉我们对方应用进程是否已读了数据。如果套接口设为非阻塞的,它将不等待close完成

作者: soqsoq   发布时间: 2010-12-16