IPC First send() and recv() calls in C++ TCP takes longer - c++

I am using IPC (Inter-process communication) to send data between two C++ programs. For the IPC I use the basic TCP/IP Winsock2 code.
Basically the idea is that I send 3D data frames between the two applications, one processes the data using GPU/CUDA and the other displays it using a 3de party library (PCL). My applications are very rich in data (ie 30fps, 4Mb per frame), but that should not be a problem for IPC as far as I know.
So as each frame is finished processing on the GPU, I convert the frames data (X,Y,Z coords of type float; R,G,B of type uint8_t each) to bytes and send them one after the other.
Doing this I have noticed something odd. In my code I have 9 send() commands one after the other.
1ste : Sending a single char that acts as the name of the frame.
2de : A single int with the amount of 3D points incoming.
3-5th : RGB values
6-8th : XYZ values
9th : End of comms check to close the viewer application.
This whole process takes ~30ms to complete. What I found odd was where most of the time went. After timing each event I got the following:
1ste : 20ms (1 byte data)
2de : <1ms (4 bytes data)
3-5 : 2ms (921600 bytes of data)
6-8 : 3ms (3686400 bytes of data)
9th : 1ms (1 byte data)
Why is it that for the first send command it takes such a long time to complete, even when its only 1 byte of data, and then the rest of the data completes in record time. In between each time this loop runs, there is about a 20ms time delay waiting for the GPU code to finish. Does the TCP connection go into a sleep state, and if so can I disable it somehow.
TCP Socket code:
SOCKET Create_Server_Socket(PCSTR IP, PCSTR port)
{
struct addrinfo *result = NULL, *ptr = NULL, hints;
int iResult;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// Resolve the local address and port to be used by the server
iResult = getaddrinfo(NULL, port, &hints, &result);
if (iResult != 0) {
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
return 1;
}
SOCKET ListenSocket = INVALID_SOCKET;
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket == INVALID_SOCKET) {
printf("Error at socket(): %ld\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
return 1;
}
iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
freeaddrinfo(result);
if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) {
printf("Listen failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
SOCKET ClientSocket;
ClientSocket = INVALID_SOCKET;
// Accept a client socket
ClientSocket = accept(ListenSocket, NULL, NULL);
if (ClientSocket == INVALID_SOCKET) {
printf("accept failed: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
return (ClientSocket);
}
Code in question:
iResult = send(ConnectSocket, (char*)&name, sizeof(char), 0); //Takes >20ms to complete
iResult = send(ConnectSocket, (char*)&points, 4, 0);
iResult = send(ConnectSocket, (char*)Red_t, sizeof(uint8_t) * depth_width *depth_height, 0);
iResult = send(ConnectSocket, (char*)Green_t, sizeof(uint8_t) * depth_width *depth_height, 0);
iResult = send(ConnectSocket, (char*)Blue_t, sizeof(uint8_t) * depth_width *depth_height, 0);
iResult = send(ConnectSocket, (char*)z_t, sizeof(uint16_t) * depth_width *depth_height, 0);
iResult = send(ConnectSocket, (char*)x_t, sizeof(float) * depth_width *depth_height, 0)
iResult = send(ConnectSocket, (char*)y_t, sizeof(float) * depth_width *depth_height, 0);
iResult = send(ConnectSocket, "a", sizeof(char), 0);
I am working on Windows 10 (ie the Winsock2 lib).
Thank you in advance!

You are probably suffering the penalty of "Nagle's Algorithm"
See https://en.wikipedia.org/wiki/Nagle%27s_algorithm
Long story short, there is a delay built-in to TCP/IP with the purpose of collecting enough data to be worth sending a packet before the first packet is sent. There is a TCP_NODELAY option that you can use when opening the socket to disable this, if it is a problem for you.
That having been said, if performance is of crucial importance, you might be better off using shared memory for inter-process communication rather than sockets.

Related

c++ WINSOCK recvfrom no get data from network

i have problem because my server dont get UDP data. Ports on router are forwarded, data income to local-server network (it is visible on sniffer (3) ) but server dont receive it.
Server and server network screen
You can see 1 and 2 TCP packets correct income to server on connected sockets. But my client then send UDP data to server and data enter to local-server network (see that sniffer detect it on 3) but server dont take it.
Here is code of client:
struct sockaddr_in si_other;
int s, slen = sizeof(si_other);
char buf[10];
char message[10];
WSADATA wsa;
//Initialise winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Initialised.\n");
//create socket
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR)
{
printf("socket() failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
//setup address structure
memset((char *)&si_other, 0, sizeof(si_other));
si_other.sin_family = AF_INET;
si_other.sin_port = htons(14996);
si_other.sin_addr.S_un.S_addr = inet_addr(server ip);
memcpy(message, "cokolwiek", 8);
//send the message
if (sendto(s, message, strlen(message), 0, (struct sockaddr *) &si_other, slen) == SOCKET_ERROR)
{
printf("sendto() failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
But its not problem with client. Here is server code but i think it is also correct:
SOCKET s;
struct sockaddr_in server, si_other;
int slen, recv_len;
char buf[10];
WSADATA wsa;
slen = sizeof(si_other);
//Initialise winsock
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
{
printf("Failed. Error Code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
printf("Initialised.\n");
//Create a socket
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == INVALID_SOCKET)
{
printf("Could not create socket : %d", WSAGetLastError());
}
printf("Socket created.\n");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(14996);
//Bind
if (::bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR)
{
printf("Bind failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
puts("Bind done");
//blocking on it, waiting for data
if ((recv_len = recvfrom(s, buf, 10, 0, (struct sockaddr *) &si_other, &slen)) == SOCKET_ERROR)
{
printf("recvfrom() failed with error code : %d", WSAGetLastError());
exit(EXIT_FAILURE);
}
//print details of the client/peer and the data received
printf("Received packet from %s:%d\n", inet_ntoa(si_other.sin_addr), ntohs(si_other.sin_port));
printf("Data: %s\n", buf);
Some description that may help - main server loop is select() and when client ask for order, server send order back to client and starts proceeding command.
server:
while (1) {
select()
if (socket is in FD_SET)
get data, send it back and handleCommand()
}
handleCommand() {
tcp data exchange
wait for udp packet - it fail
}
client:
sendCommand()
//another receiving commands thread
while (recv) {
handle command
tcp data exchange
send udp data
}
Pls dont give me answears to do it in another wait. I need to punch hole for NAT Traversal. What problem is that? Another listener grabbing my data? But netstat -nop UDP -a didn't give information that something other is listening, and bind socket didn't failed. Also another important information That code work on the begining of program, i mean server receive data but later not.
Okey, so as ElderBug said
Are you sure you setup the UDP server socket before you send the data ? It's not clear in your question
Yep, it was my fault. The miniseconds decided that sending data on one machine was executed before setting up listener on server. Thank you for answer.
But i dont exactly understand the problem. Shouldn't that data income to receive buffer and wait for "grabbing" it by recvfrom function?

Performance Windows Socket in C++ with Matlab

I am trying to create an application that sends data from a program in C++ to another in Matlab.
The size of the data is ~100 double # 1000Hz and I am having problems with reaching that frequency (even in localhost).
Using the default parameters of the socket I get ~100Hz. Also I tried using the value TCP_NODELAY to false, but that make it worse. The processor is a i7-2600 # 3.4 Hz so for sure that is not the problem. Also for the moment the only processing that I am doing with the data is save it, so also there is time consuming process.
Also I am sure that I can reach 1000 Hz because if I delete the send command, the output file has >1000 Hz.
The initialization code:
ConnectSocket = INVALID_SOCKET;
// Initialize Winsock
WSADATA wsaData;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
int iResult;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("localhost", DEFAULT_PORT, &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
}
Which is mainly (or completly) copy from the Microsoft web page.
For the sending function we have:
if (RecordingFlag){
packet[51]=values[35];
packet[52]=numchDAQ;
for (i=0;i<values[35];i++){
fprintf(file,"%.3lf,",values[i]);
packet[i] =(double)values[i];
}
//DAQ
if (numchDAQ >0){
DAQmxReadAnalogF64(taskHandle,1,10.0,DAQmx_Val_GroupByChannel,data,16,&read,NULL);
for(i=0;i<numchDAQ;i++){
fprintf(file,"%.3lf,",data[i]);
packet[(int)packet[51]+i]=(double)data[i];
}
}
//Timestamp
GetSystemTime(&st);
SystemTimeToFileTime(&st,&ft);
diftime= ((((ULONGLONG) ft.dwHighDateTime) << 32) + ft.dwLowDateTime)/10000 - MSEC_TO_UNIX_EPOCH;
fprintf(file,"%llu",diftime);
packet[0]=prueba;
prueba++;
send( ConnectSocket, (const char*)packet, sizeof(double)*53, 0 );
fprintf(file,"\n");
}
That function is called 1000 times per second.
I guess that the problem is that Windows doesn't create sockets that fast, because is waiting for the ACK from the server. But again, the server in Matlab is also very simple:
import java.net.ServerSocket
import java.io.*
j=1;
i=0;
server_socket = [];
input_socket = [];
dataByte = int8(zeros (1,424));
dataDouble = zeros(10000,53);
while (1)
try
i= i+1;
fprintf(1, 'Trying to connect %d\n',i);
server_socket = ServerSocket(31415);
server_socket.setSoTimeout(5000);
input_socket = server_socket.accept;
fprintf(1, 'Client connected\n');
while (1)
input_stream = input_socket.getInputStream;
d_input_stream = DataInputStream(input_stream);
bytes_available = input_stream.available;
while(bytes_available>0 && j<10000)
%fprintf(1, 'Reading %d bytes\n', bytes_available);
for i =1:424
dataByte(i)= d_input_stream.readByte;
bytes_available = bytes_available-1;
end
dataDouble(j,:) = typecast(dataByte,'double');
j=j+1;
end
end
% cleanup
input_socket.close;
catch
if ~isempty(server_socket)
server_socket.close;
end
if ~isempty(input_socket)
input_socket.close
end
% pause before retrying
%pause(1);
end
end
Even without make the typecast I get the same results.
Any ideas about how to solve this?
EDIT: The problem was in Matlab, it read the information too slowly. I changed the code and now works perfectly
while(bytes_available>0 && j<1000)
d_input_stream.read(dataByte,0,424);
bytes_available = bytes_available-424;
dataDouble(j,:) = typecast(dataByte,'double');
j=j+1;
end
The problem was in Matlab, it read the information too slowly. I changed the code and now works perfectly
while(bytes_available>0 && j<1000)
d_input_stream.read(dataByte,0,424);
bytes_available = bytes_available-424;
dataDouble(j,:) = typecast(dataByte,'double');
j=j+1;
end
– Priack

Writing Client and Server, UDP

I'm trying to write a simple client and server using UDP.
I can send data from the client to the server, and the server recieves it well, but when I send the data from the server to the client, it doesnt work at all...
(It doesnt detect anything, and is stuck on recvfrom function..
Here is my Server code :
SOCKET ServerOn()
{
SOCKET ListenSocket;
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
exit(0);
}
// Create a SOCKET for listening for
// incoming connection requests.
ListenSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ListenSocket == INVALID_SOCKET)
{
WSACleanup();
exit(1);
}
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("0.0.0.0");
service.sin_port = htons(2583);
if (bind(ListenSocket,(SOCKADDR *) & service, sizeof (service)) == SOCKET_ERROR)
{
closesocket(ListenSocket);
WSACleanup();
exit(2);
}
return ListenSocket;
}
In this function, I'm initializing the server on port 2583.
Here is my other code in the server :
int size = sizeof(service);
char *data = new char[500];
recvfrom(s,data, 500, NULL, (SOCKADDR*)&service, &size); // Getting a new connection
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("10.0.0.1");
service.sin_port = htons(2583);
int addrSize = sizeof(service);
if (sendto(s, "123", 3, NULL, (struct sockaddr*)&service, addrSize) != 3)
printf("%d", WSAGetLastError()); // Print error if did not send successfully
"10.0.0.1" is the IP of the Client (I made sure it is)...
I didnt found a way to get the IP automaticly from the socket, so I'm just putting it right away for now...
Here is my client code :
SOCKET ConnectToServer()
{
//----------------------
// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR)
{
return NULL;
}
//----------------------
// Create a SOCKET for connecting to server
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (ConnectSocket == INVALID_SOCKET)
{
WSACleanup();
return NULL;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr(Default_IP.c_str()); // IP
clientService.sin_port = htons(Default_Port); // Port
//----------------------
// Connect to server.
iResult = connect(ConnectSocket, (SOCKADDR *) & clientService, sizeof (clientService)); // Connecting
while (iResult == SOCKET_ERROR) // ERROR, could not connect. keep trying
{
iResult = connect(ConnectSocket, (SOCKADDR *) & clientService, sizeof (clientService)); // Connecting
}
return ConnectSocket;
}
In this code, I'm connecting to the client.
and here is the rest of the client code :
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("10.0.0.1");
service.sin_port = htons(2583);
s = ConnectToServer();
sendto(s, "123", 3, NULL, (struct sockaddr*)&service, addrSize);
while(true)
{
result = recvfrom(s, (char*)waveIn, NUMPTS * sizeof(short int), NULL, (struct sockaddr *)&service, &addrSize);
if (result > 0)
{
std::cout << "New Data!" << std::endl;
}
else
printf("%d\n", WSAGetLastError());
}
the sendto function in the client does work, and the server recieves it, though when the server tries to send data back to the client, it recieves nothing, and it is stuck on the recvfrom function.
What am I doing wrong?
P.S - I'm running both client and server from the same computer, which means both has the same IP adress ("10.0.0.1"), but it allways worked for me when using sockets with TCP, so I've did it here too.
though, I did try use this code with 2 different computers, and I still had the same error...
Thanks!
When the server calls recvfrom(), it reports the IP:Port that the data came from. You need to send your reply back to that same IP:Port, eg:
sockaddr_in service;
int size = sizeof(service);
char data[500];
int len = recvfrom(s, data, 500, NULL, (SOCKADDR*)&service, &size);
if (len == -1)
printf("recv failed: %d", WSAGetLastError()); // Print error if did not recv successfully
else
{
if (sendto(s, "123", 3, NULL, (struct sockaddr*)&service, size) == -1)
printf("send failed: %d", WSAGetLastError()); // Print error if did not send successfully
}

C++ Builder XE2, receiving tcp requests

I want to write a tcp-listener within my application, so it can be controlled by others applications.
For that I use the following snippet I found (as an example for the use of listener).
I worked with p2p-connections and Sockets once already in C#.NET, but it's either too long ago or too differently. I expect the code to stop at the listen() command and wait until there is a connection request at that port. However, instead it just continues with the next lines. Usually my Firewall should also tell me, if there is some internet-activity-attempt, but it stays silent.
What would be the next step to actually know whether there is a connection request?
Can I trigger that with a HTTP-request for 127.0.0.1:27015 using a browser?
Or could this be archived easier?
#include <winsock.h>
#pragma comment(lib, "Ws2_32.lib")
int portlisten(){
WSADATA wsaData;
int iResult = 0;
SOCKET ListenSocket = INVALID_SOCKET;
sockaddr_in service;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != NO_ERROR) {
wprintf(L"WSAStartup() failed with error: %d\n", iResult);
return 1;
}
//----------------------
// Create a SOCKET for listening for incoming connection requests.
ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ListenSocket == INVALID_SOCKET) {
wprintf(L"socket function failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
//----------------------
// The sockaddr_in structure specifies the address family,
// IP address, and port for the socket that is being bound.
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("127.0.0.1");
service.sin_port = htons(27015);
iResult = bind(ListenSocket, (SOCKADDR *) & service, sizeof (service));
if (iResult == SOCKET_ERROR) {
wprintf(L"bind function failed with error %d\n", WSAGetLastError());
iResult = closesocket(ListenSocket);
if (iResult == SOCKET_ERROR)
wprintf(L"closesocket function failed with error %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
//----------------------
// Listen for incoming connection requests
// on the created socket
if (listen(ListenSocket, 5) == SOCKET_ERROR)
wprintf(L"listen function failed with error: %d\n", WSAGetLastError());
wprintf(L"Listening on socket...\n");
iResult = closesocket(ListenSocket);
if (iResult == SOCKET_ERROR) {
wprintf(L"closesocket function failed with error %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
WSACleanup();
return 0;
}
I expect the code to stop at the listen() command and wait until there is a connection request at that port.
No. You are thinking of accept() instead. listen() merely opens the port and then exits immediately. You have to then use accept() in a loop to accept individual client connections. It returns a new SOCKET that you use to exchange data with that specific client. You can use select() to know when a new client is trying to connect before then calling accept(), or you can let accept() block the calling thread until a client connects.
Instead of writing your own socket API code, you should use a pre-existing TCP server component, like the VCL's native TServerSocket component, or Indy's TIdTCPServer component.

Getting random 10060 (conn. timeout) errors on a server socket

A few users of my software have come to me recently, telling me that it doesn't work on Windows 8. After investigation it turns out that for some strange reason, my server socket doesn't always accept connections, but lets them time out.
Even stranger: it also happens when connecting to localhost, not just when accessing it remotely.
"What have you tried?"
Obvious stuff: turn off firewalls (no effect), see if other software does work (it does), try modifying random lines of code (no effect).
Less obvious stuff: use a global WSAStartup instead of one per client or server instance (no effect).
Reminder: the exact same code works fine on Windows XP and Windows 7 and it affects localhost connections as well (not a hardware issue). Also, only a third of the connections fail, the rest works fine.
Okay, now some real code, since that's a lot more useful than all these words.
Socket setup:
int iResult;
struct addrinfo *result = NULL;
struct addrinfo hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
// "Resolve" our localhost
iResult = getaddrinfo(NULL, port, &hints, &result);
if (iResult != 0) {
printf("error (2) : %d\n", iResult);
return false;
}
// Create the socket
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (listenSocket == INVALID_SOCKET) {
freeaddrinfo(result);
printf("error (3) : %d\n", WSAGetLastError());
return false;
}
// Bind it
iResult = bind(listenSocket, result->ai_addr, result->ai_addrlen);
if (iResult == SOCKET_ERROR) {
freeaddrinfo(result);
closesocket(listenSocket);
printf("error (4) : %d\n", WSAGetLastError());
return false;
}
freeaddrinfo(result);
// Listen
iResult = listen(listenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
closesocket(listenSocket);
printf("%d\n", WSAGetLastError());
return false;
}
As you can probably see, it's almost directly taken from MSDN and should be fine. Besides, it works for 2/3 of the connections so I really doubt it's the setup code at fault.
The receiver code:
if (listenSocket == INVALID_SOCKET) return false;
#pragma warning(disable:4127)
fd_set fds;
SOCKET client;
do {
FD_ZERO(&fds);
FD_SET(listenSocket, &fds);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
if (!select(1, &fds, NULL, NULL, &timeout)) continue; // See you next loop!
struct sockaddr_in addr;
socklen_t addrlen = sizeof(addr);
// Accept the socket
client = accept(listenSocket, (struct sockaddr *)&addr, &addrlen);
if (client == INVALID_SOCKET) {
printf("[HTTP] Invalid socket\n");
closesocket(listenSocket);
return false;
}
// Set a 1s timeout on recv()
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
setsockopt(client, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv));
// Receive the request
char recvbuf[513];
int iResult;
std::stringbuf buf;
clock_t end = clock() + CLOCKS_PER_SEC; // 1s from now
do {
iResult = recv(client, recvbuf, 512, 0);
if (iResult > 0) {
buf.sputn(recvbuf, iResult);
} else if (iResult == 0) {
// Hmm...
} else {
printf("[HTTP] Socket error: %d\n", WSAGetLastError());
break;
}
} while (!requestComplete(&buf) && clock() < end);
This code spits out a "[HTTP] Socket error: 10060" error, so any code that comes after it is fairly irrelevant.
The select call is there because the actual loop does some other things as well, but I left it out because it's not socket-related.
Even stranger: Windows seems to be making actual network errors, according to Wireshark: http://i.imgur.com/BIrbD.png
I've been trying to figure this out for a while now, and I'm probably just doing something stupid, so I really appreciate all your answers.
I've been working on this annoying issue for an entire day now, and managed to eventually resolve it by rewriting the entire server from scratch and implementing it differently. I did trace the issue back to setsockopt which doesn't seem to take SO_RCVTIMEO very well anymore, causing the timeout to go to zero seconds which makes random connections time out.
My new implementation no longer uses a timeout, and is now simply non-blocking and asynchronous. Works very well but it takes a lot more code.
I'll assume that it's simply a bug in Windows 8 that will be fixed with an update before it's released. I doubt that Microsoft wanted to change the Berkeley Sockets API like this.
In Windows, SO_RCVTIMEO option requieres DWORD argument in MILLISECONDS, but not a timeval structure.
See http://msdn.microsoft.com/en-us/library/windows/desktop/ms740476(v=vs.85).aspx.
Passing timeval causes windows to interpret it as DWORD, and seconds member is read as it is milliseconds.
I don't know why timeval argument worked in Win prior 8, probably it was undocumented feature, which was removed in win 8.