我正在尝试使用 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];
现在我通过网络发送这个字符缓冲区:
client_send(buffer);
//receiving frame from server
receive_data(buffer);
函数如下所示:
客户端(发送):
#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;
}
服务器部分(接收)- 我目前将代码截断到一个客户端:
const int BUFFER_SIZE = 1000000;//1MB
...
int receive_client(_client *current_client, char *buffer, int size)
{
if (FD_ISSET(current_client->socket, ¤t_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;
}
结果变得随机困惑,就像帧在 XY 平面上随机移动一样,并且随着时间的推移移动是恒定的(尽管不同 session 不同):
我已确保正确的流以 ~
符号开头,但我不知道该转变的性质。
最佳答案
所以解决方案是:
没有必要以额外的小块发送/接收,如果带宽允许,您可以使用每个数据包 1MB。问题是一开始发送/接收的数据包长度可能不同(等一下,我会解释什么是 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,
所以解决方案是在图像的开头添加一个可靠的打开序列:[strbegin][...image data..]
并接收 1MB 数据包,在那里搜索打开序列:
/* BUFFER_SIZE = 1000000 */
int receive_client(_client *current_client, char *buffer, int size)
{
if (FD_ISSET(current_client->socket, ¤t_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 block 到达):
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);
}
您可以在上面看到,此代码在几步之后与数据到达同步,在第一遍中读取了整个 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。因此接收方需要修改才能从大量 block 中重新组合数据(请注意,当没有数据被读取时我没有打破循环,因为服务器更新现在比数据到达更快):
int receive_client(_client *current_client, char *buffer, int size)
{
if (FD_ISSET(current_client->socket, ¤t_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);
}
从里面看是怎样的:
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,
关于c++ - Winsock 移动数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43005600/