I'm trying to transmit a large chunk of data using WinSock2 from my Ubuntu Server (running wine) to my Windows Client.
This is the client code:
int expected_length = 0;
recv(m_Socket, (char*)&expected_length, 4, 0);
if (expected_length <= 0)
return;
unsigned char* buffer = new unsigned char[expected_length];
int total_read = 0;
while (total_read < expected_length)
{
int to_read = expected_length - total_read;
int count = recv(m_Socket, (char*)buffer + total_read, to_read, 0);
if (count <= 0) {
delete[] buffer;
return nullptr;
}
total_read += count;
}
This is the Server code:
send(client_sock, (const char*)&nsize, 4, 0);
int total_sent = 0;
const char* ptr = buffer.data;
while (total_sent < nsize)
{
int rest = nsize - total_sent;
int chunk = std::min(4096, rest);
int sent = send(client_sock, ptr + total_sent, chunk, 0);
if (sent < 0)
break;
std::cout << "sent: " << sent << ", total_sent: " << total_sent << std::endl;
total_sent += sent;
}
Initialization for the Socket on the Client:
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
m_Socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_Socket < 0)
return false;
sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(25010);
inet_pton(AF_INET, "127.0.0.1", &servAddr.sin_addr);
if (connect(m_Socket, (sockaddr*)&servAddr, sizeof(servAddr)) < 0)
return false;
return true;
Now to my Issue:
You are not checking the return value of send() or recv() when exchanging the 4-byte data length. You need to make sure that all 4 bytes are being transmitted/received correctly. You already have logic to do that for the data buffer, just do it for the data length, too.
Also, for good measure, you should use fixed-sized integer types for socket data, and send integers in network byte order (big endian), especially for consistency when crossing platform boundaries.
Try something more like this:
#ifndef WINDOWS
using SOCKET = int;
using TIMEVAL = struct timeval;
#endif
int lastSocketError()
{
#ifdef WINDOWS
return WSAGetLastError();
#else
return errno;
#endif
}
bool isNonBlockingSocketError(int err)
{
#ifdef WINDOWS
return (err == WSAEWOULDBLOCK);
#else
return (err == EAGAIN || err == EWOULDBLOCK || err == EINTR);
#endif
}
bool recv_all(SOCKET s, void *buffer, size_t length)
{
unsigned char *data = static_cast<unsigned char *>(buffer);
size_t total_recv = 0;
while (length > 0)
{
int result = recv(s, data, length, 0);
if (result < 0)
{
int err = lastSocketError();
if (!isNonBlockingSocketError(err))
{
std::cout << "Unable to receive data, recv error " << err << '\n';
return false;
}
fd_set fd;
FD_ZERO(&fd);
FD_SET(s, &fd);
TIMEVAL tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
result = select(s+1, &fd, nullptr, nullptr, &tv);
if (result < 0)
{
err = lastSocketError();
std::cout << "Unable to receive data, select error " << err << '\n';
return false;
}
else if (result == 0)
{
std::cout << "Unable to receive data, timed out\n';
return false;
}
}
else if (result == 0)
{
std::cout << "Unable to receive data, disconnected\n";
return false;
}
else
{
total_recv += result;
data += result;
length -= result;
std::cout << "recv: " << result << ", total_recv: " << total_recv << '\n';
}
}
return true;
}
bool recv_int32(SOCKET s, int32_t *value)
{
bool result = recv_all(s, value, 4);
if (result) *value = ntohl(*value);
return result;
}
...
int32_t expected_length = 0;
if (!recv_int32(m_Socket, &expected_length)) {
// error handling ...
}
// allocate buffer to expected length...
if (!recv_all(m_Socket, buffer, expected_length)) {
// error handling ...
}
/* alternatively:
unsigned char chunk[1024];
while (expected_length > 0)
{
int chunk_size = std::min(expected_length, 1024);
if (!recv_all(m_Socket, chunk, chunk_size)) {
// error handling ...
}
// use chunk up to chunk_size as needed...
expected_length -= chunk_size;
}
*/
bool send_all(SOCKET s, const void *buffer, size_t length)
{
const unsigned char *data = static_cast<const unsigned char *>(buffer);
size_t total_sent = 0;
while (length > 0)
{
int result = send(s, data, length, 0);
if (result < 0)
{
int err = latSocketError();
if (!isNonBlockingSocketError(err))
{
std::cout << "Unable to send data, send error " << err << '\n';
return false;
}
fd_set fd;
FD_ZERO(&fd);
FD_SET(s, &fd);
TIMEVAL tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
result = select(s+1, nullptr, &fd, nullptr, &tv);
if (result < 0)
{
err = lastSocketError();
std::cout << "Unable to send data, select error " << err << '\n';
return false;
}
else if (result == 0)
{
std::cout << "Unable to send data, timed out\n';
return false;
}
}
else
{
total_sent += result;
data += result;
length -= result;
std::cout << "sent: " << result << ", total_sent: " << total_sent << '\n';
}
}
return true;
}
bool send_int32(SOCKET s, int32_t value)
{
value = htonl(value);
return send_all(s, &value, 4);
}
...
if (!send_int32(client_sock, nsize)) {
// error handling ...
}
if (!send_all(client_sock, buffer.data, nsize)) {
// error handling ...
}