Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.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++ 发出双over TCP套接字的发送/接收向量(缺少数据)_C++_Sockets_Vector_Send_Recv - Fatal编程技术网

C++ 发出双over TCP套接字的发送/接收向量(缺少数据)

C++ 发出双over TCP套接字的发送/接收向量(缺少数据),c++,sockets,vector,send,recv,C++,Sockets,Vector,Send,Recv,我试图通过TCP套接字从向量发送数据。 我正在处理一个向量,我用0到4999的值填充它,然后将它发送到套接字 客户端,我将数据接收到一个向量中,然后将其数据复制到另一个向量,直到我从服务器接收到所有数据 我面临的问题是,当我收到数据时,有时我会得到所有数据,有时我只会收到从0到1625的正确数据,然后我会得到垃圾数据,直到最后(请参见下图)。例如,我甚至收到了从0到2600的正确数据,然后从2601到3500它是垃圾,最后从3501到4999它又是正确的 (左栏为行号,右栏为数据) 这是服务器

我试图通过TCP套接字从向量发送数据。 我正在处理一个向量,我用0到4999的值填充它,然后将它发送到套接字

客户端,我将数据接收到一个向量中,然后将其数据复制到另一个向量,直到我从服务器接收到所有数据

我面临的问题是,当我收到数据时,有时我会得到所有数据,有时我只会收到从0到1625的正确数据,然后我会得到垃圾数据,直到最后(请参见下图)。例如,我甚至收到了从0到2600的正确数据,然后从2601到3500它是垃圾,最后从3501到4999它又是正确的


(左栏为行号,右栏为数据)

这是服务器端:

向量值2;

for(int i=0;i
recv
接收字节,不一定要等待发送的所有数据。因此,您可以接收双字节的一部分

如果收到完整的
double
值,则代码可以工作,但当收到部分值时,代码将失败。您应该在
char
缓冲区中接收数据,然后将其解压为double。(如果服务器和客户端不同,则可能会转换endianness。)

#包括//用于memcpy
std::数组msgbuf;
双d;
字符数据[sizeof(double)];
int结转=0;
做{
int b=recv(sock,&msgbuf[carryover],msgbuf.size()*sizeof(msgbuf[0])-carryover,0);
字节+=b;
b+=结转量;
常量char*mp=&msgbuf[0];
而(b>=sizeof(双)){
char*bp=数据;
对于(int i=0;i
这使用类型punning from将接收到的二进制数据转换为double,并假设客户端和服务器的端号相同

顺便说一句,接收者如何知道它正在接收多少个值?您的服务器代码中混合了硬编码值(
5000
)和动态值(
.size()

注意:未编译或测试的代码

TL/DR: 永远不要通过网络套接字发送原始数据,并期望它们在另一端正确接收/解包

详细答案: 网络是建立在各种协议之上的,这是有原因的。一旦你发送了一些东西,就不能保证你的交易对手是在同一个操作系统和同一个软件版本上。没有标准的基本类型应该如何在字节级别编码。没有限制数据传递中可以涉及多少间歇节点,以及每个send()都可以通过不同的路由进行遍历。因此,您必须正式确定发送数据的方式,然后另一方可以确定从套接字检索数据的正确方式

最简单的解决方案:在数据之前使用一个标题。因此,您计划发送5000个双字节?然后首先发送一个DWORD,其中包含40000个内部元素(5k个元素,每个8字节->40k)然后,你的对手应该先从套接字中读取4个字节,将其解释为DWORD,然后理解应该有多少字节

下一步:您可能不仅要发送双精度,还要发送整数和字符串。这样,您就必须展开标题,以便它可以指示

  • 进一步数据的总大小(所谓的有效负载大小)
  • 数据类型(双精度数组、字符串、单整数等)
高级解决方案: 查看现成的解决方案:

  • ProtoBuf
  • Boost.Serialization
  • 阿帕奇节俭
  • 亚斯

快乐编码!

字节的倍数吗?@1201程序我想是的,因为1字节是8位?谢谢你的回答,在你的代码中有几点我不明白。首先,当你做recv时,你将返回值存储在“bytes b”中。我猜它是b=recv(…)。然后你做“bytes+=b”,但是字节是一个字符数组,那么这行做什么呢?为了让接收者知道它正在接收多少值,我想把大小放在向量的第一个元素中,然后从服务器发送。我也可以先发送大小,然后再发送数据。@Juju我修正了代码中的一些错误。要么先发送大小,要么使用固定数量的元素很好,但你应该保持一致,而不是混合样式。是的,我知道,我正在使用更大的数据数组,所以我实现这个向量只是为了测试。这就是为什么我使用硬编码值。你的
char*base=&msgbuf[0]是什么
用于?我明天会尝试你的解决方案,我会让你知道的!@Juju
base
的声明是从早期版本的代码中遗留下来的。我在编写代码时删除了它的使用,而忽略了删除声明。感谢你提供的详细解决方案!当以DWORD格式发送标题时,我如何指示哪个t接下来是数据类型?DWORD定义为无符号长,那么为什么要读取4个字节?DWORD是双字,字是2个字节,所以DWORD必须是4个字节(可以使用uint32_t获得相同的结果)。根据类型指示:将此类类型视为Variant(COM Variant或Boost::Variant),通常它需要额外的字段来存储枚举值,谢谢我会看的!
#include <cstring>    // For memcpy

std::array<char, 1024> msgbuf;
double d;
char data[sizeof(double)];
int carryover = 0;

do {
    int b = recv(sock, &msgbuf[carryover], msgbuf.size() * sizeof(msgbuf[0]) - carryover, 0);
    bytes += b;
    b += carryover;
    const char *mp = &msgbuf[0];
    while (b >= sizeof(double)) {
        char *bp = data;
        for (int i = 0; i < sizeof(double); ++i) {
            *bp++ = *mp++;
        }
        std::memcpy(&d, data, sizeof(double));
        final.push_back(d);
        b -= sizeof(double);
    }
    carryover = b % sizeof(double);
    // Take care of the extra bytes.  Copy them down to the start of the buffer
    for (int j = 0; j < carryover; ++j) {
        msgbuf[j] = *mp++;
    }
} while (bytes < sizeof(double) * 5000);