简体   繁体   English

C套接字编程,1个客户机读可多次写

[英]C Socket Programming, 1 Client read reads multiple writes

In my code, the client will initiate a request to server, upon so, server will keep sending data to client until a special output is presented (say "END") then client will stop reading. 在我的代码中,客户端将向服务器发起请求,此后,服务器将继续向客户端发送数据,直到出现特殊输出(例如“ END”)为止,然后客户端将停止读取。 Here's some code (just an example): 这是一些代码(仅作为示例):

/**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);

This code works fine, but due some context switching in processes, the server writes twice before the client reads, so the client reads two lines at once, say: 这段代码可以正常工作,但是由于在进程中进行了一些上下文切换,服务器在客户端读取之前写入了两次,因此客户端一次读取了两行,例如:

5532127 5532127

332 332

65723 65723

8912 8912

2421 2421

1268 1268

32END 32END

As seen, sometimes 2 or more writes are grouped into 1 read, and as a result of course the END isn't handled as it is combined.. 如图所示,有时将2个或更多的写操作分组为1个读操作,因此结果END不会被合并处理。

I tried using usleep() function, which works most of the time, but still isn't a solution. 我尝试使用usleep()函数,该函数大多数时候都有效,但仍然不是解决方案。 So any idea how I make sure the server doesn't write to buffer if it is not empty? 因此,有什么主意如何确保服务器在不为空的情况下不会写入缓冲区?

You are using a stream oriented socket. 您正在使用面向流的套接字。 The server can't know if client has already received the data or not, and there's not really any difference between your multiple writes in a loop, or just one write which sends the whole array. 服务器无法知道客户端是否已经接收到数据,并且循环中的多次写入或发送整个数组的一次写入之间实际上没有任何区别。

You will need to use something packet oriented, or have a way to figure out what are your "packets". 您将需要使用面向数据包的东西,或者有一种方法可以弄清什么是“数据包”。 As you've figured out, you can't rely on timings, so you'll need to define some sort of protocol. 如您所知,您不能依赖时序,因此您需要定义某种协议。 Something simple would be to just read the ints*, and have a special value as end. 简单的方法是只读取ints *,并以特殊值作为结尾。

Btw. 顺便说一句。 your code also has a couple of issue with number representation. 您的代码在数字表示方面也存在一些问题。 You need to used a fixed length type (int can be 16 or 32-bit, so use something like uint32_t), and you need to be aware of endianess issues (should probably use htonl/ntohl or similar). 您需要使用固定长度的类型(int可以是16位或32位,因此请使用uint32_t之类的东西),并且需要注意字节序问题(可能应该使用htonl / ntohl或类似的东西)。

I can see some problems in your code. 我可以在您的代码中看到一些问题。

You use a strtok(readline, "\\n"); 您使用strtok(readline, "\\n"); client side while sending raw int server side. 客户端,同时发送原始int服务器端。 It means that in one of the sent integers is 0x..10 or 0x10.. it will be changed to (resp.) 0x..00 or 0x00.. . 这意味着在发送的整数之一中为0x..100x10..它将更改为(分别) 0x..000x00.. Never use strxx functions on raw bytes ! 切勿在原始字节上使用strxx函数!

Next, you are using stream oriented sockets. 接下来,您将使用面向流的套接字。 You can have no assurance that packets send will not be grouped or splitted. 您不能保证发送的数据包不会被分组或拆分。 So you should collate everything in the receiver until you have 3 consecutive chars containing END . 因此,您应该整理接收器中的所有内容,直到连续3个包含END字符为止。 But you cannot use strxx function for that ... 但是您不能strxx使用strxx函数...

Finally, you transfer raw integer, and wait for 3 characters END. 最后,您传输原始整数,并等待3个字符END。 But if you try to send {12, 17743, 17408, 13} (on a big-endian system) you will have a major problem : 17743 = 0x454F, and 17408 = 0x4400 => you have exactly "END" ! 但是,如果您尝试发送{12, 17743, 17408, 13} (在大端系统上),则会遇到一个主要问题:17743 = 0x454F和17408 = 0x4400 =>您正好是“ END”! On a little endian, the magic values would be 20293 = 0x4F45 and 68 = 0x0044. 在小端上,魔术值将为20293 = 0x4F45和68 = 0x0044。

The rules are : 规则是:

  • in you want to transer binary data, you should use a lenght + packet pattern because any pattern can happen in raw data. 在要转换二进制数据时,应使用长度+数据包模式,因为任何模式都可能在原始数据中发生。 And a good practice is to convert all data longer than one byte to network order ( htonx functions) to avoid endianness problems 一个好的做法是将所有超过一个字节的数据转换为网络顺序( htonx函数),以避免字节顺序问题
  • if you want to use delimiters, you should only use character data, ensuring (via escaping or ...) that the end pattern cannot occur in data. 如果要使用定界符,则应仅使用字符数据,以确保(通过转义或...)结束符不会出现在数据中。

In you use case, you should simply tranfer textual representation, converting integer using sprintf , separating them with space, end terminating with \\n . 在用例中,您应该简单地转移文本表示形式,使用sprintf转换整数,将它们用空格分隔,以\\n结尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C套接字编程-服务器的write()写入服务器而不是客户端 - C socket programming - write() from server writes to server instead of client 服务器套接字中的多次写入到客户端套接字程序中的单次读取? - Multiple writes in server socket to single read in client socket program? 套接字编程read()正在读取我的所有写入() - Socket programming read() is reading all of my writes() Linux C编程:对同一文件描述符的并发读/写 - Linux C Programming: Concurrent reads/writes to same file descriptor 服务器在 C 套接字编程中无需等待读取客户端命令即可继续进行 - Server proceeding without waiting to read client command in C socket programming 如何在套接字编程中从telnet客户端读取服务器上的参数c - How to read an argument at a server from a telnet client in socket programming c C socket编程——TCP Server和Client的读写不同步 - C socket programming - Read and Write of TCP Server and Client out of sync 在管道上进行多次读取和写入 - Multiple reads and writes on the pipe 套接字编程将多个客户端连接到一台服务器并列出它们C - socket programming connect multiple client to one server and list them C 读取系统调用返回垃圾并读取比写入系统调用在套接字中写入的次数更多 - read syscall returns trash and reads more times than write syscall writes in a socket
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM