简体   繁体   English

部分发送/接收TCP套接字c ++

[英]Partial send/receive TCP Sockets c++

I am struggling with TCP networking, especially with partial sending and receiving. 我在TCP网络方面苦苦挣扎,尤其是在部分发送和接收方面。 I was reading Beej`s tutorial for sockets and I am trying to achieve things he mentioned in paragraph"data encapsulation"-> create communication code invulnerable for partial send/recv. 我正在阅读Beej的套接字教程,并且正在尝试实现他在“数据封装”->创建对于部分发送/接收无害的通信代码中提到的内容。 I have a function that sends in loop as long as the whole packet is sent and now I am working on the receiving part. 只要有整个数据包被发送,我就有一个循环发送的功能,现在我正在接收部分工作。 Every time I send something, I create a packet first which contains the packet length, source address, destination address and message itself. 每次发送邮件时,我都会首先创建一个数据包,其中包含数据包的长度,源地址,目标地址和消息本身。 These fields are separated from each other using special characters like "$"or"/". 这些字段使用特殊字符(例如“ $”或“ /”)彼此分隔。 It looks like this: 看起来像这样:

$packet_length/source_addr%dest_addr<message>

Then I have a function that receives first and check whether it got the whole packet or not (finds special chars to create substring which indicates the packet length and then check if the buffer has all data or not). 然后,我有一个函数,该函数首先接收并检查是否收到了整个数据包(查找特殊字符以创建表示数据包长度的子字符串,然后检查缓冲区是否包含所有数据)。 If it received part of packet it gets into loop and calls recv() as long as it gets the full packet. 如果接收到部分数据包,则进入循环并在获取完整数据包时调用recv() In theory it should work fine but it`s theory ... During test everything works fine (send the whole packet at once and receives it as well) and I am trying to simulate the condition where I send only half of the packet -> I force the send func to send only 16 bytes of the packet(which is 32 bytes long). 从理论上讲,它应该可以正常工作,但是从理论上讲...在测试过程中,一切都很好(一次发送整个数据包并也接收它),我正在尝试模拟只发送一半数据包的情况->我强制发送函数仅发送数据包的16个字节(长度为32个字节)。 On the receiving part I get the message but 22 bytes long(not 16) and with some garbage(random chars). 在接收部分,我收到消息,但消息的长度为22个字节(不是16),并且带有一些垃圾(随机字符)。 What is going wrong? 怎么了? Where are theses garbage come from? 这些垃圾从哪里来? Here is the code: 这是代码:

Sending func: 发送功能:

int sendall( int s, const char *order, const char *from, const char *destination)

{

    const char *buf = marshal(order,from, destination).c_str();
 // moving the packet(returned by marshal func) to the buf

    unsigned int len = strlen(buf);

    int total = 0; // sent bytes
    int bytesleft = len; // bytes left to send
    int n;


    while( total <  len ) {
        n = send( s, buf+total, bytesleft, 0 );
        if( n == - 1 ) { break; }
        total += n;
        bytesleft -= n;
    }


    return n ==- 1 ?- 1: 0; // returns -1 when fails, 0 - success
}

Receiving func: 接收功能:

int recieveall(int socket){

int n;

 n = recv( socket, buf, sizeof(buf), 0 );  // recieves message

    string packet(buf);

// searching for the packet length which is placed beetween $ and /

    int dollar_sign = packet.find("$");
    int slash = packet.find("/");

    buf_temp[0] = '\0';
    string packet_len = packet.substr(dollar_sign+1, slash-(dollar_sign+1) );

// checking if recieved full packet or a part of it -> comparing bufer length with packet size
// if not calls recieve in a loop untill gets the whole packet

    while(strlen(buf) < stoi(packet_len)){


        int total = strlen(buf);
        int left = stoi(packet_len)-total;

        n = recv( socket, buf_temp, left, 0 );

        left -= n;
        total +=n;

        if(total = stoi(packet_len)) {break;}

    }

    if(buf_temp[0] != '\0'){strcat(buf, buf_temp);} // concat 2 buffers to get the whole message


    if(n == 0){return n = 0;}
    if(n == -1){return n =-1;}
    if(n > 0){return n ;}


}

If it is important the recieveall() is called in accept loop and I use select() as well. 如果很重要,则在accept循环中调用recieveall() ,我也使用select()。 I will appreciate any help or advise. 我将不胜感激任何帮助或建议。

  • You shouldn't assume the buffer is ever null-terminated. 您不应该假定该缓冲区是空终止的。
  • You should keep a running total of the bytes received so far and stop reading when you get there. 到目前为止,您应该保持运行中的字节总数,并在到达该位置时停止读取。
  • You should test the return value of recv() for -1 (error) and zero (end of stream) and take the appropriate (different) action in each case. 您应该测试recv()的返回值是否为-1(错误)和零(流结束),并在每种情况下采取适当的(不同的)动作。

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

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