简体   繁体   中英

Winsock shifts data

I am trying to send image frames over the network using Winsock. I know array length and their dimensions, so I'm just using a char buffer of sufficient constant size. The following conversion works fine and in real time:

char buffer[BUFFER_SIZE]; //BUFFER_SIZE = 1000000
...
UINT16 *pBuffer = NULL; //send buffer
UINT16 *pBuffer2 = NULL; //receive buffer
...
//copying to the buffer of correct length to avoid errors. 
//Empirically found that it seems contiguous
memcpy(&buffer[1], pBuffer, nBufferSize*2);//img is int16, nBufferSize*2 ~ 400000
buffer[0] = '~'; //adding special symbol to mark correct data stream

// here supposed to be send-receive with buffer

//convert received result back to UINT16
pBuffer2 = (UINT16*)&buffer[1];

Here is how correct image from pBuffer2 looks like: 良好的深度图像

Now I'm sending this char buffer over the network:

client_send(buffer);

//receiving frame from server   

receive_data(buffer);

Where the functions look like the following:

Client part (send):

#define DEFAULT_BUFLEN 1000000 //1MB
...
int client_send(char *sendbuf) {

    // Send an initial buffer

        //iResult = send(ConnectSocket, sendbuf, (int)strlen(sendbuf), 0);
        iResult = send(ConnectSocket, sendbuf, DEFAULT_BUFLEN, 0);
        if (iResult == SOCKET_ERROR) {
            printf("send failed with error: %d\n", WSAGetLastError());
            closesocket(ConnectSocket);
            WSACleanup();
            return 1;
        }

        printf("Bytes Sent: %ld\n", iResult);       

    return 0;
}

Server part (receive) - I truncated the code to one client at the moment:

const int BUFFER_SIZE = 1000000;//1MB
...
int receive_client(_client *current_client, char *buffer, int size)
{
    if (FD_ISSET(current_client->socket, &current_client->socket_data))
    {
        // Store the return data of what we have sent
        current_client->address_length = recv(current_client->socket, buffer, size, 0);

        if (current_client->address_length == 0)
        { // Data error on client
            disconnect_client(current_client);

            return (FALSE);
        }

        return (TRUE);
    }

    return (FALSE);
}

int receive_data(char* buffer)
{
    //char buffer[BUFFER_SIZE];

    for (int j = 0; j < MAX_CLIENTS; j++)
    {
        if (client[j].connected)
        {
            if (receive_client(&client[j], buffer, BUFFER_SIZE))
            {
                if (buffer[0] == '~') {
                    // if we have correct packet                    
                    return 1;
                    //buffer[0] = '/0';
                } 
            }
        }
    }

    return 0;
}

The result becomes randomly messed up like frame was randomly shifted in XY plane, and the shift is constant over time (though different for different sessions):

depth_ugly

I have ensured that correct stream begins with ~ symbol and I have no idea on the nature of that shift.

So the solution is:

There is no need to send/receive in extra small chunks, you may use 1MB per packet if bandwidth allows to do it. The problem is that length of packets send/received may differ at first (wait a second, I will explain what is buffer2):

SOCKET ESTABLISHED
Binding socket:0
Socket Bound to port : 4000
ACCEPTING CLIENT to array position [0] with IP ADDRESS 127.0.0.1
buffer received: -1, 
Bytes Sent: 1000000
buffer received: 992800, 
got beg. packet
buffer2 received: 7200, 
Bytes Sent: 1000000
buffer received: 1000000, 
got beg. packet
buffer2 received: 0, 
Bytes Sent: 1000000
buffer received: 1000000, 
got beg. packet
buffer2 received: 0, 
Bytes Sent: 1000000
Bytes Sent: 1000000
buffer received: 1000000, 
got beg. packet
buffer2 received: 0, 

So the solution is to add a reliable opening sequence at the beginning of the image: [strbegin][...image data..] and receive 1MB packets, searching for the opening sequence there:

/* BUFFER_SIZE = 1000000 */

int receive_client(_client *current_client, char *buffer, int size)
{
    if (FD_ISSET(current_client->socket, &current_client->socket_data))
    {
         char smallbuffer[BUFFER_SIZE]; //secondary incoming buffer
         current_client->address_length = recv(current_client->socket, smallbuffer, BUFFER_SIZE, 0); //recv returns the number of bytes received 

         if (current_client->address_length == 0)
            { // Data error on client
                disconnect_client(current_client);

                return (FALSE);
            }

            printf("buffer received: %d, \n", current_client->address_length);

            char * pch = strstr(smallbuffer, strbegin); //searching for the opening sequence

When you encountered it, you need to copy the rest of the smallbuffer into the resulting variable and read next packet. But be careful, as the packet received may be shorter than 1MB! So you need to take the number of bytes received into account (the data is not lost, it just arrives with the next TCP chunk):

if (pch != nullptr) { // if we encountered the beginning in some way

    printf("got beg. packet\n");

    int position = pch - smallbuffer; // pointer subtraction, http://stackoverflow.com/questions/7500892/get-index-of-substring

    int substringLength = (current_client->address_length) - position;

    memcpy(&buffer[0], pch, substringLength); // copy the rest of the data into buffer

    current_client->address_length = recv(current_client->socket, &buffer[substringLength], size-substringLength, 0); //read the rest of the message 

    printf("buffer2 received: %d, \n", current_client->address_length);

}

You can see above that this code synchronized with data arrival after few steps, reading entire 1MB message in first pass. Also some frame drop is possible in this code, but my live transfer does not demand precision.

By the way, my server is not blocking, otherwise program hangs:

// This makes the server non blocking, hence it won't wait for a response
    unsigned long b = 1;
    ioctlsocket(server_socket, FIONBIO, &b);

EDIT: Well, after I switched from localhost to real LAN network, I found that real size of messages transferred is about 40KB. So the receiving side needs modification to be able to reassemble the data from a big number of chunks (notice that I'm not breaking the loop when no data was read, as server update works faster now than data arrives):

int receive_client(_client *current_client, char *buffer, int size)
{
    if (FD_ISSET(current_client->socket, &current_client->socket_data))
    {

        //attempt first read into secondary buffer
            current_client->address_length = recv(current_client->socket, smallbuffer, BUFFER_SIZE, 0); //recv returns the number of bytes received 

            if (current_client->address_length == 0)
            { // Data error on client
                disconnect_client(current_client);

                return (FALSE);
            }

            printf("buffer received: %d, \n", current_client->address_length);

            char * pch = strstr(smallbuffer, strbegin); //searching for the opening sequence

            if (pch != nullptr && (current_client->address_length > 0)) { // if we encountered the beginning in some way

                printf("got beg. packet\n");

                int position = pch - smallbuffer; // pointer subtraction, http://stackoverflow.com/questions/7500892/get-index-of-substring

                int substringLength = (current_client->address_length) - position;

                memcpy(&buffer[0], pch, substringLength); // copy the rest of the data into buffer

                int tmpsize = size - substringLength;   // how many we still need to read

                int count = 1;
                int where_we_are = substringLength;
                do  // repeat until buffer is filled
                {
                    current_client->address_length = recv(current_client->socket, smallbuffer, tmpsize, 0); //read the next chunk
                    substringLength = current_client->address_length; // how much we read this time

                    if (substringLength > 0){
                        memcpy(&buffer[where_we_are], smallbuffer, substringLength); //add it to buffer

                        where_we_are += substringLength;
                        tmpsize = tmpsize - substringLength;
                        count++;
                    }
                    else {
                        //tmpsize = 0; // nope, can't break - need to read until the end ! Seems like reading is performed faster than data arrival
                    }
                } while (tmpsize > 0);

                printf("buffer2 received: %d chunks \n", count);


            }


        return (TRUE);
    }

How it looks like from inside:

buffer received: -1, 
buffer received: 182500, 
got beg. packet
buffer2 received: 356 chunks 
buffer received: -1, 
buffer received: -1, 
buffer received: -1, 
buffer received: -1, 
buffer received: -1, 
buffer received: -1, 
buffer received: -1, 
buffer received: 589840, 
got beg. packet
buffer2 received: 238 chunks 
buffer received: -1, 
buffer received: 589940, 
got beg. packet
buffer2 received: 168 chunks 
buffer received: -1, 
buffer received: 562936, 
got beg. packet
buffer2 received: 227 chunks 
buffer received: -1, 
buffer received: 590140, 
got beg. packet
buffer2 received: 204 chunks 
buffer received: -1, 
buffer received: 590240, 

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