高频插座通信

时间:2013-06-09 06:15:42

标签: c++ c sockets

我需要每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
...

6 个答案:

答案 0 :(得分:5)

TCP套接字不保证框架。当您通过TCP套接字发送字节时,这些字节将以相同的顺序在另一端接收,但它们不一定以相同的方式分组 - 它们可以以任何方式分割,组合在一起或重新组合操作系统认为合适。

如果您需要成帧,则需要发送某种数据包标头以指示每个数据块的开始和结束位置。这可以采用分隔符(例如,\n\0来指示每个块结束的位置)或长度值(例如,每个块的头部的数字来表示如何很长时间。)

此外,正如其他受访者所指出的那样,sleep()取整数,所以你实际上根本就没有睡觉。

答案 1 :(得分:3)

sleepunsigned int为参数,因此sleep(0.02)实际上是sleep(0)

unsigned int sleep(unsigned int seconds);

请改用usleep(20)。它会在几微秒内睡觉:

int usleep(useconds_t usec);

答案 2 :(得分:2)

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

除了睡眠采用无符号整数。

答案 3 :(得分:2)

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

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

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

根据您的其他要求,UDP也可能是一个很好的解决方案。

答案 4 :(得分:2)

sleep(0.02)

实际上是

sleep(0) 

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

'\0'

某些实现中的

字符。

答案 5 :(得分:2)

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

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

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

您可以通过非常简单的方式进行自己的构建,例如,首先发送一个整数,表示消息的剩余时间。在读取器端,您将读取整数,然后读取该字节数。对于下一条消息,您将发送另一个整数,表示该消息的持续时间等等。

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

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

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