如何在套接字编程中发送长度大于缓冲区的消息?

我正在使用C ++中的Winsock开发一个应用程序。 我有一个200字节长的char数组,用于通过套接字发送字符串。

我的问题是当发送大于char数组的消息时,所以我决定以多个块发送它们,但我不知道该怎么做。

为了发送和接收数据,我使用常规的send()recv()函数:

 recv(client, buffer, 200, NULL); send(client, buffer, 200, NULL); 

更新

我有一个结构:

 struct Pack { unsigned int senderId; char str[200]; } 

在发送之前我将struct转换为char数组。

 Pack pk; strcpy_s(pk.str, 200, "Some text to send.\0"); pk.senderId = 1 // user id char *buffer = (char*)pk; 

如果字符串大小如果大于200则strcpy_s()崩溃。

你在Beej的网络编程指南中有一个例子:

7.3。 处理部分send()

请记住上面关于send()的部分,当我说send()可能不会发送你要求它的所有字节时? 也就是说,你希望它发送512个字节,但它返回412.剩下的100个字节发生了什么?

好吧,他们还在你的小缓冲区等待被送出去。 由于你无法控制的情况,内核决定不在一个块中发送所有数据,而现在,我的朋友,由你来获取数据。

您也可以编写这样的函数来执行此操作:

 int sendall(int s, char *buf, int *len) { int total = 0; // how many bytes we've sent int bytesleft = *len; // how many we have left to send int n; while(total < *len) { n = send(s, buf+total, bytesleft, 0); if (n == -1) { break; } total += n; bytesleft -= n; } *len = total; // return number actually sent here return n==-1?-1:0; // return -1 onm failure, 0 on success } 

编辑:正如@a​​lk指出的那样,用ssize_t替换所有那些int - send()返回的类型

如果您正在发送或接收UDP数据包,那么就无法绕过它; 你需要一个足够大的缓冲区来容纳整个数据包。 幸运的是,在大多数情况下,您不希望发送或接收大于1500字节的UDP数据包(因为这是以太网卡可以发送的最大数据包而不会将其分成更小的数据包,并且通常您希望避免碎片,如果可能)。

对于TCP,请记住您正在发送/接收字节流,而不是一系列单独的数据包,因此传递给send()和recv()的大小通常不会对应于网络的大小然后包。 这意味着调用send()6次,每次调用100字节的数据,与使用600字节数据调用send()1次没有太大区别,依此类推。 正如其他人所指出的那样,你必须仔细检查每个send()和recv()调用的返回值,看看实际发送或接收的字节数,因为发送/接收的数量有时可能(并且会)小于您请求的字节数。 您需要知道实际发送了多少字节才能知道哪些字节适合在下次调用时发送,并且您需要知道实际接收了多少字节才能知道您的接收中有多少字节现在有效 – 缓冲。

你需要在两端缓冲。

当您send ,您无法确保将发送所有缓冲区。 send(2)系统调用可能返回部分字节计数

同样,当你的recv东西,字节流可能是部分的。 recv(2)系统调用可能返回部分字节计数。

您可能需要一些事件循环(例如,在poll(2)之上)来混合发送和接收。

TCP / IP不保证给定的send (在发射器机器中)对应于一个recv (在接收机器中):字节流可能已被分块成中间的任意部分(例如,通过路由器)。 另见这个 。

逐条发送消息。 您只能发送与发送缓冲区大小一样大的块,因此您需要记住已发送的数量和剩余的数量; 然后你可以使用循环来做所需的事情:

 int bufferSize = 200; int messageLength = 442; // or whatever int sendPosition = 0; while (messageLength) { int chunkSize = messageLength > bufferSize ? bufferSize : messageLength; memcpy(buffer, message + sendPosition, chunkSize); chunkSize = send(client, buffer, chunkSize, NULL); messageLength -= chunkSize; sendPosition += chunkSize; } 

当然你可以简单地从message发送,而不是先将一个不需要的副本bufferbuffer ,但我只是在这里说明这个概念。

然后,您的接收代码可能需要在处理之前完整地汇编消息,但这实际上取决于您设计的协议。