关闭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完成