【问题标题】:Trying to understand logic behind network communication试图理解网络通信背后的逻辑
【发布时间】:2014-03-10 15:02:51
【问题描述】:

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

服务器:

  • 创建套接字
  • 将套接字绑定到端口
  • 接受
  • 接收发送数据

在客户端:

  • 创建套接字
  • 连接
  • 接收发送

我的问题是服务器完成accept之后提出的。

想象之后 accept 在服务器端有三个单独的行 发送数据:

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 调用上下文中发生?

这是一张图片,可以更好地说明我可能对什么样的场景感兴趣:

欢迎使用伪代码解释如何处理这种连接。

【问题讨论】:

  • 假设 TCP,否 - 一次读取可以读取所有发送(取决于大小)。
  • @sje397:是的,但是如果我想分块发送数据怎么办?
  • @dmcr_code 这些块有什么意义吗?接收者是否需要将一个块与另一个块分开?如果是这样,您需要在每个块中嵌入信息,以便它们可以再次分开,例如通过在每个块的前面添加固定数量的字节,即块的长度。然后,接收者可能会进行多次 recv() 调用来接收一个块(并且它可能会在一次 recv() 调用中获得一个块的结尾和下一个块的开始的一半。
  • @dmcr_code - 您发送的大小为例如两个字节然后是消息,在另一端读取大小然后等待那么多字节

标签: c networking


【解决方案1】:

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

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

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

send(var1)  --->  recv(var1)
send(var2)  --->  recv(var2)

在普通 TCP 中没有方式(除非我什至不会指定未使用的边缘情况,因为没有人应该使用它们)您将在var1 之前收到var2

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

我再重复一遍:你在 TCP 中拥有的只是一个字节流。 TCP 不知道也不关心这些字节的结构,无论是在发送端还是在接收端。 全部由你决定。当您发送一个整数或一个数据结构时,您发送的是一个内存转储作为字节

例如,有一个常见错误是您尝试send() 数据结构并且由于发送缓冲区已满,系统将进行部分写入。如果您不检查send() 调用的返回状态来检测这种情况,然后您自己发送剩余的字节,在另一个send() 调用中,您的客户端将卡在@987654327 @ 当它需要完整的结构并且只接收它的一部分时,如果你指定了 MSG_WAITALL。

【讨论】:

  • '每个操作都会成功' - 否则您将收到错误通知。
  • @Ivan Voras:嘿,ivan,为了更好地说明我的意思,也许让我们看看这种情况。假设服务器使用三个单独的发送调用向客户端发送三个整数。如何在客户端区分这些变量?我应该在客户端调用 3 次 receive 并希望我能正确接收整数吗?
  • 是的,你可以这样做,或者你可以创建一个由三个整数组成的数组,或者一个包含三个整数的结构并接收它(如果客户端和服务器具有完全相同的架构并且编译器),或者您可以创建一个字节缓冲区,或者您可以单独接收每个字节,或者其他任何东西。由您来解释来自网络的数据,系统不会为您执行此操作。 tl;dr:是的,如果你对三个整数调用 send(),你可以通过对三个整数执行 recv() 来接收它们。
【解决方案2】:
  1. TCP 是一种流协议,在接收方你无法确定发送被调用了多少次。每当调用 recv 时,它都会给出请求读取的字节数,如果请求的字节数不可用,则返回当前套接字缓冲区中的字节数。

  2. 在 UDP 的情况下,它会像您提到的那样工作,它是一种数据报协议。 (使用 recvfrom 接收数据)

【讨论】:

  • 值得注意的是,UDP数据包可以乱序接收,有时根本收不到。
猜你喜欢
  • 2022-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-18
  • 2020-03-09
  • 1970-01-01
  • 2011-05-31
  • 1970-01-01
相关资源
最近更新 更多