Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 试图理解网络通信背后的逻辑_C_Networking - Fatal编程技术网

C 试图理解网络通信背后的逻辑

C 试图理解网络通信背后的逻辑,c,networking,C,Networking,在C语言中,要接收/发送数据,通常(大致): 服务器: 创建套接字 将套接字绑定到端口 听 接受 收发数据 在客户端: 创建套接字 连接 收发 我的问题是在服务器完成接受后提出的 想象一下,在服务器端的接受之后,有三行独立的代码 要发送数据: connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL); write(connfd, var1, var1Size); write(connfd, var2, var2Size); write

在C语言中,要接收/发送数据,通常(大致):

服务器:

  • 创建套接字
  • 将套接字绑定到端口
  • 接受
  • 收发数据
在客户端:

  • 创建套接字
  • 连接
  • 收发
我的问题是在服务器完成接受后提出的

想象一下,在服务器端的
接受
之后,有三行独立的代码 要发送数据:

connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);
write(connfd, var1, var1Size);
write(connfd, var2, var2Size);
write(connfd, var3, var3Size);
这是否意味着在客户端,我需要进行三次读取? 像这样:

read(sockfd, &x, size1);
read(sockfd, &y, size2);
read(sockfd, &z, size3);
换句话说,发送和接收呼叫应该如何对应 在服务器端和客户端?对于每个发送,客户端是否应该有相应的接收

若在客户端,在3次读取调用(如上所述)之后,我想要将数据发送到服务器,该怎么办? 我应该在客户端和服务器端分别添加一个新的发送和一个新的接收吗

所有这些发送/接收是否都应该发生在单个
accept
调用上下文中

以下是一幅更好地说明我可能感兴趣的场景的图片:


欢迎使用解释如何处理此类连接的伪代码。

除非您使用的是具有“消息”概念的协议,例如UDP,否则您所拥有的只是一个字节流。您可以按自己的意愿发送和接收它们

例如,您可以发送两个16位整数,并将其作为一个32位整数接收。这可能不是你想要的,但它是完全合法的,并且在需要的情况下一直使用。只要对应用程序有意义,就可以独立地在任意一侧(发送和接收)组合数据结构

您的字节按write()的顺序发送,您将按相同的顺序接收它们。即

send(var1)  --->  recv(var1)
send(var2)  --->  recv(var2)
在正常的TCP中(除非未使用的边缘情况,我甚至不会指定,因为没有人应该使用它们),您将无法在
var1
之前收到
var2

TCP通信是双向的:每个端点(客户端和服务器)可以同时发送。由您和您的应用程序决定何时发送和何时接收。发送和接收缓冲区是独立的:您可以发送几个字节,接收几个字节,再发送一些字节。。。它们之间不会有干扰(即,您不会通过发送一些数据来“覆盖”接收缓冲区,反之亦然)

我再重复一遍:TCP中的所有内容都是字节流。TCP不知道也不关心这些字节的结构,无论是在发送端还是在接收端。一切由你决定。当您发送一个整数或数据结构时,您将发送这些数据的内存转储(以字节为单位)

例如,有一个常见错误,您试图
send()
一个数据结构,由于发送缓冲区已满,系统将进行部分写入。如果您没有检查
send()
调用的返回状态以检测这种情况,然后自己发送剩余字节,那么在另一个
send()
调用中,如果您指定MSG\u WAITALL,当您的客户机需要完整的结构并且只接收其中的一部分时,它将陷入
recv()

  • TCP是一种流协议,在接收方,您无法确定调用发送的次数。无论何时调用recv,它都将给出请求读取的字节数,如果请求的字节数不可用,则它将返回套接字缓冲区中当前的字节数

  • 在UDP的情况下,它将像您提到的那样工作,它是一个数据报协议。(使用recvfrom记录数据)


  • 假设TCP,否-可以通过一次读取读取所有发送(取决于大小)。可能重复@sje397:是的,但是如果我想以块的形式发送数据呢?@dmcr_代码块有什么意义吗?接收者是否需要将一个区块与另一个区块分开?如果是这样,您需要在每个块中嵌入信息,以便它们可以再次分离,例如,在每个块前面添加固定数量的字节,即块的长度。然后,接收方可能会进行多个recv()调用来接收一个块(并且它可能会在一个recv()中获得一个块的末尾和下一个块的一半开头)调用。@dmcr_代码-您发送的大小为消息的两个字节,在另一端读取大小,然后等待那么多字节。值得注意的是,UDP数据包可能会被无序接收,有时甚至根本没有接收到。“每个操作都会成功”-或者您会收到错误通知。@Ivan Voras:嘿,Ivan,为了更好地说明我的意思,也许让我们看看这种情况。假设服务器使用三个单独的发送调用向客户端发送三个整数。我如何在客户端区分这些变量?我应该在客户端调用三次receive并希望适当地接收整数吗?是的,您可以这样做,或者您可以创建一个包含三个整数的数组,或者创建一个包含整数的结构e三个整数并接收(如果客户端和服务器的体系结构和编译器完全相同),或者您可以创建一个字节缓冲区,或者您可以单独接收每个字节,或者其他任何内容。由您来解释来自网络的数据,系统将不会为您这样做。tl;dr:是的,如果您调用send()对于三个整数,可以通过对三个整数执行recv()来接收它们。