English 中文(简体)
从套接字C部分接收数据包++
原标题:Partial receipt of packets from socket C++

我遇到了一个问题,我的服务器应用程序发送了8字节长的数据包-AABBCC1122334455,但我的应用程序通过“recv”函数分两部分接收到这个数据包AARBCC112233445

谢谢

问题回答

总结一下标题:

  1. TCP connection doesn t operate with packets or messages on the application level, you re dealing with stream of bytes. From this point of view it s similar to writing and reading from a file.
  2. Both send and recv can send and receive less data than provided in the argument. You have to deal with it correctly (usually by applying proper loop around the call).
  3. As you re dealing with streams, you have to find the way to convert it to meaningful data in your application. In other words, you have to design serialisation protocol.

根据你已经提到的,你很可能想发送某种信息(好吧,这通常是人们所做的)。关键是要正确地发现消息的边界。如果你的消息大小固定,你只需从流中获取相同数量的数据并将其转换为你的消息;否则,您需要一种不同的方法:

  • 如果你能想出一个消息中不存在的字符,它可能是你的分隔符。然后,您可以阅读流,直到到达角色,这将是您的消息。如果传输ASCII字符(字符串),可以使用零作为分隔符。

  • 如果您传输二进制数据(原始整数等),所有字符都可以出现在您的消息中,因此没有任何字符可以作为分隔符。在这种情况下,最常见的方法可能是使用包含消息大小的固定大小前缀。此额外字段的大小取决于消息的最大大小(使用4个字节可能是安全的,但如果你知道最大大小是多少,你可以使用较低的值)。那么你的数据包看起来就像SSSS|PPPPPPPPP(字节流),其中S是附加大小字段,PP字节数由SS字节)开头,因此您可以将它们读取为32位整数。一旦知道封装消息的大小,就可以读取所有P字节。处理完一个数据包后,您就可以从套接字中读取另一个了。

不过,好消息是,你可以想出一些完全不同的东西。你需要知道的是如何从字节流中反序列化你的消息,以及send/recv的行为。祝你好运

编辑:

函数将任意数量的字节接收到数组中的示例:

bool recv_full(int sock, char *buffer, size_t size)
{
  size_t received = 0;
  while (received < size)
  {
    ssize_t r = recv(sock, buffer + received, size - received, 0);
    if (r <= 0) break;
    received += r;
  }

  return received == size;
}

以及接收具有2字节前缀的数据包的示例,该前缀定义了有效载荷的大小(有效载荷的尺寸限制为65kB):

uint16_t msgSize = 0;
char msg[0xffff];

if (recv_full(sock, reinterpret_cast<char *>(&msgSize), sizeof(msgSize)) &&
    recv_full(sock, msg, msgSize))
{
  // Got the message in msg array
}
else
{
  // Something bad happened to the connection
}

这就是recv()在大多数平台上的工作原理。你必须检查你收到的字节数,并继续在循环中调用它,直到你得到你需要的数字。

您可以通过在循环中读取TCP套接字来“修复”这个问题,直到您获得足够的字节来理解您的应用程序。

我的服务器应用程序发送长度为8字节的数据包

不是真的。您的服务器发送8个单独的字节,而不是8个字节长的数据包。TCP数据是通过字节流而不是数据包流发送的。TCP既不尊重也不维护您可能想到的任何“数据包”边界。

如果你知道你的数据是以N字节的数量提供的,那么在循环中调用recv

std::vector<char> read_packet(int N) {
  std::vector buffer(N); 
  int total = 0, count;
  while ( total < N && (count = recv(sock_fd, &buffer[N], N-total, 0)) > 0 )
    total  += count;
  return buffer;
}

    std::vector<char> packet = read_packet(8);

如果您的数据包长度可变,请尝试在数据本身之前发送:

int read_int() {
  std::vector<char> buffer = read_packet(sizeof (int));
  int result;
  memcpy((void*)&result, (void*)&buffer[0], sizeof(int));
  return result;
}

  int length = read_int();
  std::vector<char> data = read_buffer(length); 




相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?