C套接字编程,1客户端读取读取多个写入

时间:2015-06-03 11:32:33

标签: c sockets

在我的代码中,客户端将向服务器发起请求,此时,服务器将继续向客户端发送数据,直到出现特殊输出(例如" END"),然后客户端将停止读取。 这里有一些代码(只是一个例子):

self.delegate?.childViewControllerResponse(parameter)

此代码工作正常,但由于进程中的某些上下文切换,服务器在客户端读取之前写入两次,因此客户端一次读取两行,例如:

  

5532127

     

332

     

65723

     

8912

     

2421

     

1268

     

32END

如图所示,有时2个或多个写入被分组为1个读取,因此当然结束时不会处理END。

我尝试使用/**Client**/ char req[] = "some-request"; write(socket,req,strlen(req)); while(1) { read(socket,readline,100); strtok(readline, "\n"); if(strcmp(readline,"END") == 0){ //if end of sending break; } /** HANDLE OUTPUT **/ } /** Server **/ int data[] = {5532,127,332,65,723,8,912,2,421,126,8,3,2} int i; for(i = 0 ; i < sizeof(data); i++) { write(socket, data[i], sizeof(data[i]); } write(socket, "END", 3); 功能,该功能大部分时间都有效,但仍然不是解决方案。 那么任何想法如何确保服务器在没有空的情况下不写入缓冲区?

2 个答案:

答案 0 :(得分:1)

您正在使用面向流的套接字。服务器无法知道客户端是否已经接收到数据,并且在循环中多次写入之间没有任何区别,或者只有一次写入发送整个阵列。

您将需要使用面向数据包的东西,或者有办法弄清楚您的&#34;数据包&#34;。正如您所知,您不能依赖时间,因此您需要定义某种协议。简单的方法是只读取整数*,并将一个特殊值作为结束。

顺便说一下。您的代码在编号表示方面也存在一些问题。你需要使用固定长度类型(int可以是16或32位,所以使用像uint32_t这样的东西),你需要知道endianess问题(应该使用htonl / ntohl或类似的)。

答案 1 :(得分:1)

我可以在你的代码中看到一些问题。

在发送原始int服务器端时使用strtok(readline, "\n");客户端。这意味着,在其中一个已发送的整数中,0x..100x10..会将其更改为(分别)0x..000x00..。切勿在原始字节上使用strxx函数!

接下来,您正在使用面向流的套接字。您无法保证不会对数据包发送进行分组或拆分。因此,您应该整理接收器中的所有内容,直到您有3个包含END的连续字符。但你不能使用strxx函数......

最后,传输原始整数,并等待3个字符END。但是如果你尝试发送{12, 17743, 17408, 13}(在大端系统上),你将遇到一个主要问题:17743 = 0x454F,17408 = 0x4400 =&gt;你有完全“结束”!在一个小端,魔术值将是20293 = 0x4F45和68 = 0x0044。

规则是:

  • 如果要转换二进制数据,则应使用长度+数据包模式,因为任何模式都可能发生在原始数据中。一个好的做法是将长度超过一个字节的所有数据转换为网络顺序(htonx函数)以避免字节序问题
  • 如果你想使用分隔符,你应该只使用字符数据,确保(通过转义或...)数据中不会出现结束模式。

在您的用例中,您应该简单地转移文本表示,使用sprintf转换整数,用空格分隔,最后以\n结尾。