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, ¤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;
}
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):
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, ¤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
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, ¤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);
}
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.