1

我需要每 0.02 秒向另一个进程发送数据。

服务器代码:

//set socket, bind, listen
while(1){
     sleep(0.02);
     echo(newsockfd);
 } 

void echo (int sock)
{
   int n;
   char buffer[256]="abc";
   n=send(sock,buffer,strlen(buffer),0);
   if (n < 0) error("ERROR Sending");
}

客户端代码:

//connect
while(1)
{
  bzero(buffer,256);
  n = read(sock,buffer,255);
  printf("Recieved data:%s\n",buffer);
  if (n < 0)
    error("ERROR reading from socket");
}

问题是:

客户端显示如下内容:

Recieved data:abc
Recieved data:abcabcabc
Recieved data:abcabc
....

它是如何发生的?当我设置睡眠时间时:

...
sleep(2)
...

没关系:

Recieved data:abc
Recieved data:abc
Recieved data:abc
...
4

6 回答 6

5

TCP 套接字不保证成帧。当您通过 TCP 套接字发送字节时,这些字节将在另一端以相同的顺序接收,但它们不一定会以相同的方式进行分组——它们可能会以任何方式被拆分、组合在一起或重新组合操作系统认为合适。

如果您需要成帧,则需要发送某种数据包头来指示每个数据块的开始和结束位置。这可以采用定界符的形式(例如,a\n\0表示每个块在哪里结束),或长度值(例如,每个块的头部的数字表示它有多长)。

此外,正如其他受访者指出sleep()的那样,取整数,因此您实际上根本没有在这里睡觉。

于 2013-06-09T06:26:42.840 回答
3

sleepunsigned int作为论据,实际上sleep(0.02)也是如此sleep(0)

unsigned int sleep(unsigned int seconds);

改为使用usleep(20)。它将在微秒内休眠:

int usleep(useconds_t usec);
于 2013-06-09T06:18:17.680 回答
2

操作系统可以自由缓冲数据(即为什么不只发送一个完整的数据包而不是多个数据包)

除了 sleep 需要一个无符号整数。

于 2013-06-09T06:23:35.360 回答
2

原因是操作系统正在缓冲要发送的数据。它将根据大小或时间进行缓冲。在这种情况下,您没有发送足够的数据,但是您发送的速度足够快,操作系统选择在将其连接到网络之前对其进行批量处理。

当您添加 时sleep(2),它的长度足以让操作系统选择在下一个“abc”进入之前发送一个“abc”。

您需要了解 TCP 只是一个字节流。它没有消息或大小的概念。您只需将字节放在电线的一端,然后从另一端取下。如果您想做特定的事情,那么您需要在阅读数据时以特殊的方式解释数据。因此,正确的解决方案是为此创建一个实际的协议。该协议可以像“每 3 个字节是一个消息”一样简单,或者在发送大小前缀的情况下更复杂。

UDP 也可能是一个很好的解决方案,具体取决于您的其他要求。

于 2013-06-09T06:34:05.020 回答
2

TCPIP 堆栈缓冲数据,直到有相当数量的数据,或者直到他们决定不再有来自应用程序的数据并发送他们已经获得的数据。

您需要做两件事。首先,关闭 Nagle 算法。其次,理清某种框架机制。

关闭 Nagle 的算法将导致堆栈“立即发送数据”,而不是等待您想要发送更多数据的机会。它实际上会导致网络效率降低,因为您没有填充以太网帧,在千兆位上需要考虑到需要巨型帧才能获得最佳吞吐量的情况。但在您的情况下,及时性比吞吐量更重要。

您可以通过非常简单的方式进行自己的框架,例如通过首先发送一个整数来说明消息的剩余时间。在阅读器端,您将读取整数,然后读取该字节数。对于下一条消息,您将发送另一个整数,说明该消息的长度等。

这种事情还可以,但不是非常强大。您可以查看 ASN.1 或 Google 协议缓冲区之类的内容。

我使用了 Objective System 的 ASN.1 库和工具(它们不是免费的),它们在处理消息完整性、框架等方面做得很好。它们很好,因为它们不从网络连接中读取数据一次一个字节,因此效率和速度还不错。任何额外读取的数据都会保留并包含在下一个消息解码中。

我自己没有使用过 Google Protocol Buffers,但它们可能具有相似的特性,并且可能还有其他类似的序列化机制。出于速度/效率的原因,我建议避免 XML 序列化。

于 2013-06-09T07:33:50.680 回答
2
sleep(0.02)

有效地

sleep(0) 

因为参数是无符号整数,所以隐式转换会为您完成。所以你在这里根本睡不着。您可以使用sleep(2)休眠 2 微秒。接下来,即使您有,也不能保证您的消息将在不同的帧中发送。如果你需要这个,你应该应用某种分隔符,我见过

'\0'

在某些实现中的字符。

于 2013-06-09T07:00:23.607 回答