简体   繁体   中英

Losing data when sending by UDP

I've written a UDP send/receive function to send a struct and listen for another struct back. The bytes have to be sent in a particular order, but this is working OK as I'm using #pragma pack(1) . The only problem that I'm having now is that if any Null values ( 0x00 ) appear in the struct, the rest of the data after the Null disappears.

I guess there's something fairly simple that I'm doing wrong, but here is my code:

typedef u_int8_t NN;
typedef u_int8_t X;
typedef int32_t S;
typedef u_int32_t U;
typedef char C;

typedef struct{
    X test;
    NN test2[2];
    C test3[4];
    S test4;
} Test;

int main(int argc, char** argv)
{
    Test t;
    memset( &t, 0, sizeof(t));
    t.test = 0xde;
    t.test2[0]=0xad; t.test2[1]=0x00;
    t.test3[0]=0xbe; t.test3[1]=0xef; t.test3[2]=0xde; t.test3[3]=0xca;
    t.test4=0xde; 

    LogOnResponse response;

    udp_send_receive(&t, &response);

    return 0;
}

And here is my send/receive function:

int send_and_receive(void* message, void* reply, int do_send, int expect_reply)
{
    struct sockaddr_in serv_addr;
    int sockfd, i, slen=sizeof(serv_addr);
    int buflen = BUFLEN;
    void* buf = NULL;
    struct timeval tv;
    int n_timeouts=1;
    int recv_retval;

//  printf("Message Size: %d\n", strlen(message));

    if ( (strlen(message)) >= BUFLEN)
        err("Message too big");

    buf = malloc(buflen);

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1)
        err("socket");

    tv.tv_sec = timeout_seconds;
    tv.tv_usec = timeout_microseconds;
    if( setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) < 0 ){
        err("Setting Timout"); 
    }

    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    if (inet_aton(IP_ADDRESS, &serv_addr.sin_addr)==0)
        err("inet_aton() failed\n");

    //---Timeout Send/Receive loop

    do{
    if(do_send == TRUE){
        strcpy(buf, message);
        if (sendto(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, slen)==-1)
            err("sendto()");
    }

    if (expect_reply == TRUE){
        if( (recv_retval = recvfrom(sockfd, buf, buflen, 0, (struct sockaddr*)&serv_addr, &slen)) == -1){
            itercount++;    
        }
    }

    }while ((itercount < itermax) && (recv_retval == -1));

    if ( itercount != itermax ){
        memcpy(reply, buf, BUFLEN);
    }
    else{
        reply=NULL;
    }

    close(sockfd);
    free(buf);
    return 0;
}

void udp_send_receive(void* message, void* reply)
{
    send_and_receive(message, reply, TRUE, TRUE);
}

Running the above code and capturing the packets with WireShark shows:

Data: DEAD000000000000000000....

I'd like it to show:

Data: DEAD00BEEFDECADE

I'd really appreciate some pointers on this.

You can't use string functions (like strlen or strcpy ) for binary data. It's because strings are terminated by the value zero (character '\\0' ).

For example, you use strcpy to copy data, but it will stop as soon as is sees the string terminator meaning it will not copy all of the data.

而不是使用strcpy使用

void * memcpy ( void * destination, const void * source, size_t num );

Doing strcpy(buf, message); in send_and_receive() is incorrect. I would update code to pass size of message and use that to copy memory as

udp_send_receive(&t, sizeof(t), &response);



void udp_send_receive(void* message, int len, void* reply){

    send_and_receive(message, len reply, TRUE, TRUE);
}

int send_and_receive(void* message, int len, void* reply, int do_send, int expect_reply){

   ...
   int buflen = len;

   ....
   memcpy(buf, message, len); //instead of strcpt(buf, message)

   ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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