Performance Windows Socket in C++ with Matlab - c++

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

Related

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

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.

Non-IOCP client send/recv error with IOCP server

Please understand that I am new to IOCP and my code may not be so perfect.
I tried many examples from around here, neither one helps me.
My actual problem is in the client side, I have no idea if I am connecting properly to a IOCP server, neither if I send the data properly and recv gives me WSAerror 10038 ...
WSADATA wsd;
struct addrinfo *result = NULL, *ptr = NULL, hints;
WSAOVERLAPPED RecvOverlapped;
SOCKET ConnSocket = INVALID_SOCKET;
WSABUF DataBuf;
DWORD RecvBytes, Flags;
CRITICAL_SECTION criti;
char buffer[DATA_BUFSIZE];
int err = 0;
int rc;
// Load Winsock
rc = WSAStartup(MAKEWORD(2, 2), &wsd);
if (rc != 0) {
return 1;
}
// Make sure the hints struct is zeroed out
SecureZeroMemory((PVOID)& hints, sizeof(struct addrinfo));
// Initialize the hints to retrieve the server address for IPv4
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
rc = getaddrinfo(IP, Port, &hints, &result);
if (rc != 0) {
return 1;
}
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
if ((ConnSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) == INVALID_SOCKET){
freeaddrinfo(result);
return 1;
}
rc = connect(ConnSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (rc == SOCKET_ERROR) {
if (WSAECONNREFUSED == (err = WSAGetLastError())) {
closesocket(ConnSocket);
ConnSocket = INVALID_SOCKET;
continue;
}
freeaddrinfo(result);
closesocket(ConnSocket);
WSACleanup();
return 1;
}
break;
}
if (ConnSocket == INVALID_SOCKET) {
freeaddrinfo(result);
return 1;
}
int nZero = 0;
// Make sure the RecvOverlapped struct is zeroed out
SecureZeroMemory((PVOID)& RecvOverlapped, sizeof(WSAOVERLAPPED));
// Create an event handle and setup an overlapped structure.
RecvOverlapped.hEvent = WSACreateEvent();
if (RecvOverlapped.hEvent == NULL) {
freeaddrinfo(result);
closesocket(ConnSocket);
return 1;
}
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;
// send data to server here?
// removed the packets, it`s not supposed to be public
// Call WSARecv until the peer closes the connection
// or until an error occurs
while (1) {
Flags = 0;
RecvBytes = 0;
rc = WSARecv(ConnSocket, &DataBuf, 1, &RecvBytes, &Flags, &RecvOverlapped, NULL);
if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
closesocket(ConnSocket);
break;
}
rc = WSAWaitForMultipleEvents(1, &RecvOverlapped.hEvent, TRUE, INFINITE, TRUE);
if (rc == WSA_WAIT_FAILED) {
break;
}
rc = WSAGetOverlappedResult(ConnSocket, &RecvOverlapped, &RecvBytes, FALSE, &Flags);
if (rc == FALSE) {
break;
}
// here I have a protocol where I read the received data
WSAResetEvent(RecvOverlapped.hEvent);
// If 0 bytes are received, the connection was closed
if (RecvBytes == 0)
break;
}
WSACloseEvent(RecvOverlapped.hEvent);
closesocket(ConnSocket);
freeaddrinfo(result);
WSACleanup();
I expect to be able to send data and receive the response from IOCP, but if I send 3 packets, I receive back 2 only or sometimes even 1, when I am sending 3 packets back.
Can some show me a working example to connect and send+recv data to a IOCP server?
Many thanks!
You're using TCP. TCP is a stream protocol, not a datagram protocol. You cannot tell it what packets to send, and it cannot tell you what packets it received (it doesn't even know because that's handled at the IP layer). It just doesn't work that way.
This sentence is packed with wisdom: "TCP is a bidirectional, connection oriented, byte stream protocol that provides reliable, ordered delivery but does not preserve application message boundaries." Punch "TCP" into your favorite search engine and study until you understand precisely what every word in that sentence means. You will never write reliable, or even correct, TCP code until you do.
Whether the server is using IOCP or some other internal architecture has no effect on clients. That's totally invisible.

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.