繁体   English   中英

发出TCP套接字上的double的发送/接收向量(丢失数据)

[英]Issue sending/Receiving vector of double over TCP socket (missing data)

我正在尝试通过TCP套接字从向量发送数据。 我正在使用向量填充0至4999的向量,然后将其发送到套接字。

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

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

包含接收数据的文件
(左列是行号,右列是数据)。

这是服务器端:

vector<double> values2;
for(int i=0; i<5000; i++)
    values2.push_back(i);
skt.sendmsg(&values2[0], values2.size()*sizeof(double));

sendmsg函数:

void Socket::sendmsg(const void *buf, size_t len){

    int bytes=-1;

    bytes = send(m_csock, buf, len, MSG_CONFIRM);

    cout << "Bytes sent: " << bytes << endl;

}

客户端 :

vector<double> final;
vector<double> msgrcvd(4096);

do{

    bytes += recv(sock, &msgrcvd[0], msgrcvd.size()*sizeof(double), 0);
    cout << "Bytes received: " << bytes << endl;

    //Get rid of the trailing zeros
    while(!msgrcvd.empty() && msgrcvd[msgrcvd.size() - 1] == 0){
        msgrcvd.pop_back();

    }

    //Insert buffer content into final vector
    final.insert(final.end(), msgrcvd.begin(), msgrcvd.end());


}while(bytes < sizeof(double)*5000);


//Write the received data in a txt file

for(int i=0; i<final.size(); i++)
    myfile << final[i] << endl;

myfile.close();


字节的输出正确,服务器在发送数据时输出40 000,客户端在接收数据时也输出40 000。

删除尾随的零,然后将缓冲区的内容插入到新的向量中不是很有效,但是我认为这不是问题。 如果您对如何提高效率有任何线索,那就太好了!

我真的不知道问题出在何时发送或何时接收数据,我也不清楚为什么有时(很少)获得所有数据。

recv接收字节 ,并且不一定等待所有已发送的数据。 因此,您可以接收双打的一部分。

如果您收到完整的double值,则您的代码将起作用,但是当您收到部分值时,代码将失败。 您应该在char缓冲区中接收数据,然后将其解压缩为双精度。 (如果服务器和客户端不同,则可能转换字节顺序。)

#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);

这使用类型修剪的方式是:将浮点型的类型修剪为int的正确方法,反之亦然? 将接收到的二进制数据转换为double并假定客户端和服务器的字节序相同。

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

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

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

详细答案:网络是建立在各种协议之上的,这是有原因的。 一旦发送邮件,您的交易对手就不会在同一操作系统和同一软件版本上享有任何保证。 没有标准的字节类型应如何编码原始类型。 没有限制,可以在数据传递中涉及多少个间歇节点,并且每个send()都可以通过不同的路径遍历。 因此,您必须规范发送数据的方式,然后另一方可以确定从套接字检索数据的正确方法是什么。

最简单的解决方案:在数据前使用标头。 那么,您打算发送5000双打吗? 然后先发送一个DWORD,里面包含40000个(5k个元素,每个8个字节-> 40k),然后紧接着推送所有5k双打。 然后,您的交易对手应该首先从套接字读取4个字节,将其解释为DWORD,然后了解应该传入多少字节。

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

  • 其他数据的总大小(所谓的有效负载大小)
  • 数据种类(双精度数组,字符串,单整数等)

先进的解决方案:看一下现成的解决方案:

编码愉快!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM