C套接字客户端/服务器延迟问题

7
我正在编写一个C/C++客户端/服务器套接字应用程序。目前,客户端每50毫秒连接一次服务器并发送一条消息。
一切似乎都正常工作,但数据流不是连续的:突然间,服务器不再收到任何消息,然后5条消息一起到来……有时一切正常……
有人知道这种奇怪行为的原因吗?
代码的一部分:
客户端:
while (true)
{
if (SDL_GetTicks()-time>=50)
{
socket = new socket();
socket->write("blah");
message.clear();
message = socket->read();
socket->close();
delete socket;
time=SDL_GetTicks();
}
}

服务器:

while (true) {
fd_set readfs;
struct timeval timeout={0,0};
FD_ZERO(&readfs);
FD_SET(sock, &readfs);
select(sock + 1, &readfs, NULL, NULL, &timeout)
if(FD_ISSET(sock, &readfs))
{
SOCKADDR_IN csin;
socklen_t crecsize = sizeof csin;
SOCKET csock = accept(sock, (SOCKADDR *) &csin, &crecsize);
sock_err = send(csock, buffer, 32, 0);
closesocket(csock);
}
}

Edits: 1. I tried to do

int flag = 1;
setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof flag);

无论在客户端还是服务器端,问题仍然存在。

2.是的,这些连接/断开连接非常低效,但当我尝试编写时

socket = new socket();
while (true)
{
if (SDL_GetTicks()-time>=50)
{
socket->write("blah");
message.clear();
message = socket->read();
time=SDL_GetTicks();
}
}

然后消息只会发送一次(或接收)...

最后:

我忘记在服务器端将TCP_NODELAY应用于客户端套接字。现在它完美地工作了! 我将进程放入线程中,以便套接字保持打开状态。 谢谢大家 :)

3个回答

9

我总是被这里的人们的知识所吸引。非常感谢。我一会儿会尝试一下 :) - Klaus

6

正如其他人已经回复的那样,您看到的延迟是由TCP内置的Nagle算法引起的,可以通过设置TCP_NODELAY套接字选项来禁用该算法。

我想指出的是,由于不断的连接和断开连接,您的套接字通信非常低效。每次客户端连接到服务器时都会进行三次握手,而连接的撤销需要四个数据包才能完成。基本上,您失去了TCP的大部分优势,但承担了所有的缺点。

对于每个客户端来说,与服务器保持持久连接要更加高效。在Linux上,使用select(2),甚至更好的是epoll(4),在FreeBSD和Mac上使用kqueue(2),这些都是处理多个套接字IO的非常方便的框架。


1
不仅仅是握手和拆除连接,每次建立新连接时,您都需要再次经历慢启动。 - ephemient
2
@Klaus,你需要在双方都进行这些更改,而不仅仅是客户端。因为服务器在第一次读取后会关闭每个连接。此外,TCP不能保证套接字的单个写入对应于另一侧的单个读取。通常都是在循环中完成这两个操作。然后你的应用程序协议需要验证接收到的字节。 - Nikolai Fetissov

3
您可以使用TCP_NODELAY套接字选项来强制立即发送数据。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接