C++ Winsock移动数据

C++ Winsock移动数据,c++,winsock,C++,Winsock,我正在尝试使用Winsock通过网络发送图像帧。我知道数组长度和它们的维数,所以我只是使用一个大小足够恒定的char缓冲区。以下转换工作正常且实时: char buffer[BUFFER_SIZE]; //BUFFER_SIZE = 1000000 ... UINT16 *pBuffer = NULL; //send buffer UINT16 *pBuffer2 = NULL; //receive buffer ... //copying to the buffer of correct le

我正在尝试使用Winsock通过网络发送图像帧。我知道数组长度和它们的维数,所以我只是使用一个大小足够恒定的
char
缓冲区。以下转换工作正常且实时:

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];
下面是来自
pBuffer2
的正确图像的外观:

现在我通过网络发送这个字符缓冲区:

client_send(buffer);

//receiving frame from server   

receive_data(buffer);
其中函数如下所示:

客户端部分(发送):

服务器部分(接收)-目前我将代码截断为一个客户端:

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;
}
const int BUFFER\u SIZE=1000000//1MB
...
int接收_客户端(_客户端*当前_客户端,字符*缓冲区,int大小)
{
if(FD_ISSET(当前_客户端->套接字,&当前_客户端->套接字数据))
{
//存储我们发送的返回数据
当前客户端->地址长度=recv(当前客户端->套接字,缓冲区,大小,0);
如果(当前客户端->地址长度==0)
{//客户端上的数据错误
断开_客户端(当前_客户端);
返回(假);
}
返回(真);
}
返回(假);
}
int接收_数据(字符*缓冲区)
{
//字符缓冲区[缓冲区大小];
对于(int j=0;j
结果会变得随机混乱,就像帧在XY平面上随机移动一样,并且随着时间的推移,移动是恒定的(尽管对于不同的会话不同):

我已经确保正确的流以
~
符号开始,我不知道这种转变的性质

因此解决方案是:

不需要以额外的小块发送/接收,如果带宽允许,您可以使用1MB的每个数据包。问题是,发送/接收的数据包的长度一开始可能不同(请稍等,我将解释什么是缓冲区2):

因此,解决方案是在图像的开头添加一个可靠的打开序列:
[strbegin][…图像数据..]
并接收1MB数据包,在那里搜索打开序列:

/* 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
遇到它时,需要将
smallbuffer
的其余部分复制到结果变量中,然后读取下一个数据包。但是要小心,因为接收到的数据包可能小于1MB!因此,您需要考虑接收到的字节数(数据不会丢失,它只是与下一个TCP块一起到达):

您可以在上面看到,经过几个步骤后,该代码与数据到达同步,在第一次传递时读取整个1MB消息。在这段代码中也可能出现一些帧丢失,但我的实时传输不需要精确性

顺便说一下,我的服务器没有阻塞,否则程序将挂起:

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

编辑:嗯,在我从本地主机切换到真正的LAN网络后,我发现传输的消息的实际大小约为40KB。因此,接收方需要修改,以便能够从大量数据块中重新组装数据(请注意,在没有读取数据的情况下,我并没有中断循环,因为服务器更新现在比数据到达的速度更快):

从内部看是什么样子:

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, 
因此,解决方案是:

不需要以额外的小块发送/接收,如果带宽允许,您可以使用1MB的每个数据包。问题是,发送/接收的数据包的长度一开始可能不同(请稍等,我将解释什么是缓冲区2):

因此,解决方案是在图像的开头添加一个可靠的打开序列:
[strbegin][…图像数据..]
并接收1MB数据包,在那里搜索打开序列:

/* 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
遇到它时,需要将
smallbuffer
的其余部分复制到结果变量中,然后读取下一个数据包。但是要小心,因为接收到的数据包可能小于1MB!因此,您需要考虑接收到的字节数(数据不会丢失,它只是与下一个TCP块一起到达):

您可以在上面看到,经过几个步骤后,该代码与数据到达同步,在第一次传递时读取整个1MB消息。在这段代码中也可能出现一些帧丢失,但我的实时传输不需要精确性

顺便说一下,我的服务器没有阻塞,否则程序将挂起:

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

编辑:嗯,在我从本地主机切换到真正的LAN网络后,我发现传输的消息的实际大小约为40KB。因此,接收方需要修改,以便能够从大量数据块中重新组装数据(请注意,在没有读取数据的情况下,我并没有中断循环,因为服务器更新现在比数据到达的速度更快):

从内部看是什么样子:

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, 

我可能弄错了(只是看不到我在代码中寻找什么)。发送的图像缓冲区将被拆分为多个数据包,需要在客户端重新组装。此外,多个发送的图像将相互连接,不要求数据包边界位于图像边界。@RichardCriten谢谢!我只是在上面的代码中使用了
send
/
recv
,具有恒定大小的字符数组,对于文本消息来说效果很好,我需要做什么才能正确地重新组合图像块?一种方法是消息格式,例如[图像长度][图像]。其中,前4个字节是图像数据后跟图像数据的长度。在接收端循环重新组装图像,直到[length of image]字节添加到图像缓冲区。您可以使用[message type][message length][message]来扩展此功能,以实现更广泛的交换。@RichardCriten据我所知,我有与您描述的相同的设置:我知道两侧的图像大小
nBufferSize*2
(转换为
uint16
),并且我正在接收一条带有单个缓冲区的消息
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,