LINUX下TCP程序问题,为何服务端会延迟一会儿收到客户端的数据

dablyo 2007-02-06 06:52:19
linux下的c程序作为服务端,客户端是java程序。
服务端使用非阻塞socket,每隔一秒定时接收一次,客户端每隔5秒发送心跳信息,此外客户端不定时发送指令数据,要求服务端回应此指令。

现在的问题是服务端经常会延迟(远大于1秒)收到客户端的指令,若客户端关闭发送心跳数据,则服务端经常会在客户端第二次发送指令的时候才收到第一次的数据。似乎是后一次发送的数据将前一次的数据由协议层‘挤’到socket层的。

后来我又把socket改为阻塞的,采用线程方式,效果类似,不知道原因在哪里?

代码见下面

服务端socket初始化部分
if (srvsock > 0)
{
shutdown(srvsock, SHUT_RDWR);
close(srvsock);
}

srvsock = socket(AF_INET, SOCK_STREAM, 0);
if (srvsock < 0)
return (BOOLEAN)1; /*log it */
i = fcntl(srvsock, F_SETFL, O_NONBLOCK);
if (i < 0)
{
shutdown(srvsock, SHUT_RDWR);
close(srvsock);
return (BOOLEAN)1; /*log it */
}
k = 1;
v = 1;

i = setsockopt(srvsock, SOL_SOCKET, SO_REUSEADDR, &k, sizeof(int));
if (i < 0)
{
shutdown(srvsock, SHUT_RDWR);
close(srvsock);
return (BOOLEAN)1; /*log it */
}

local.sin_family = AF_INET;
local.sin_addr.s_addr = INADDR_ANY;
local.sin_port = htons(MTRACE_TCP_PORT);
i = bind(srvsock, (struct sockaddr *)&local, sizeof(local));
if (i < 0)
{
shutdown(srvsock, SHUT_RDWR);
close(srvsock);
return (BOOLEAN)1; /*log it */
}
i = listen(srvsock, MAX_CLIENT_NUM);
if (i < 0)
{
shutdown(srvsock, SHUT_RDWR);
close(srvsock);
return (BOOLEAN)1; /*log it */
}

接收部分
while ((j = recv(sockid, msgbuf, sizeof(msgbuf), 0/*MSG_NOSIGNAL*/)) > 0)
{
/ *process... */
}
if (j == 0) /*peer closed */
{
/* close */
}
else if (j < 0)
{
if (errno != EAGAIN)
{
/* close */
}
}

...全文
620 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
gettext 2007-02-21
  • 打赏
  • 举报
回复
code贴的不全,肯定是程序问题。 或者改一下结构用select 或者 epoll.
prozilla 2007-02-18
  • 打赏
  • 举报
回复
禁用 nagle 算法;如果你的系统上附带的编程手册里对 nagle 只字不提,你可以扔掉这个系统了。
darkone 2007-02-07
  • 打赏
  • 举报
回复
应该是while ((j = recv(sockid, msgbuf, sizeof(msgbuf), 0/*MSG_NOSIGNAL*/)) > 0)
sizeof(msgbuf)的长度大于你发包的实际长度,只有收到sizeof(msgbuf)大小的包后才做后面的处理
johndiyang 2007-02-07
  • 打赏
  • 举报
回复
具体原因我不知道
linux c socket对数据的处理比较快,接收到不完整的包就会以一个完整的包处理,尤其是刚开始的几个字节,估计是同步异常造成的。
解决办法:在包头设置校验信息,收到完整的校验信息的包一般才是正确地。
dablyo 2007-02-06
  • 打赏
  • 举报
回复
补充一个
在accept时,设置客户端对应socket的非阻塞属性,如下:

fd = accept(srvsock, (struct sockaddr *)&addr, (socklen_t *)&j);
if (fd > 0)
{
fcntl(fd, F_SETFL, O_NONBLOCK);
k = setsockopt(fd,SOL_SOCKET,SO_SNDBUF,&maxsndbuf,4);
if ( k != 0)
......
}
dablyo 2007-02-06
  • 打赏
  • 举报
回复
自己顶

查了socket section 7,上面说
SO_RCVLOWAT and SO_SNDLOWAT
Specify the minimum number of bytes in the buffer until the socket layer will pass the data to the protocol (SO_SNDLOWAT) or the user on receiving (SO_RCVLOWAT). These two values are not changeable in Linux and their argument size is always fixed to 1 byte. getsockopt is able to read them; setsockopt will always return ENOPROTOOPT.

抓包器抓包的结果可以确定客户端发的数据已经发送到了服务端的机器里,貌似协议层没有通知应用层来收这些数据。只到下一次数据的到来。根据上面的描述应该不是因为SO_RCVLOWAT的问题。

23,118

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧