I have an app written in C using the Win32 API for Windows 7 and higher.
The app streams ASCII g-code command strings to a multi axis router controller.
The controller can be communicated with using either a USB COM Serial Port or an Ethernet socket.

The streaming via COM serial port is working fine. I am having latency issues with the ethernet socket.
I have tried to adopt the same overlapped IO strategy for the ethernet that works great for the COM port.
This is my first time trying to use WinSock, and I am pretty sure that I am overlooking something.

In both cases I am using asyncronous overlapped IO. In both cases a separate thread is launched to constantly read the output from the controller back to the application.
The primary thread streams the sequential g-codes to the controller while the separate read thread accepts reponses.

Here are the code sections for both the COM port and the ethernet socket.

First, the COM port is created in this manner:

Code:
struct SyncVariables
{
	OVERLAPPED oswriter;
	HANDLE serialport;
	bool readthreadrunning;
	bool controllerisconnected;
	bool readport;
};

SyncVariables sync;

sync.oswriter = {0};
sync.serialport = NULL;
sync.readthreadrunning = false;
sync.controllerisconnected = false;
sync.readport = true;

if ((sync.serialport = CreateFile(L"\\\\.\\COM7", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL)) != INVALID_HANDLE_VALUE)
{
	DCB dcb = {0};
	dcb.DCBlength = sizeof(DCB);
	GetCommState(sync.serialport, &dcb);
	dcb.BaudRate = CBR_115200;						
	dcb.Parity = NOPARITY;
	dcb.StopBits = ONESTOPBIT;
	SetCommState(sync.serialport, &dcb);
	GetCommState(sync.serialport, &dcb);

	COMMTIMEOUTS timeouts = {0};
	timeouts.ReadIntervalTimeout = MAXDWORD;
	timeouts.ReadTotalTimeoutMultiplier = 0;
	timeouts.ReadTotalTimeoutConstant = 0;
	timeouts.WriteTotalTimeoutMultiplier = 0;
	timeouts.WriteTotalTimeoutConstant = 0;
	SetCommTimeouts(sync.serialport, &timeouts);

	DWORD portmask = EV_RXCHAR;
	SetCommMask(sync.serialport, portmask);

	sync.oswriter.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	_beginthread(&ReadComPortThread, 0, &sync);
	
	while(sync.readthreadrunning == false) // wait till we know readportthread is running before writing to port
	{
		Sleep(200);
	}

	WriteToComPort("IsControllerConnected\n", &sync);

	Sleep(200); // give time for readcomportthread to respond for this initialization

	if (sync.controllerisconnected == true)
	{
		// send g-codes to controller
		WriteToComPort("G0 X1000 Y1000\n", &sync);
		WriteToComPort("G0 X6000 Y1000\n", &sync);
		WriteToComPort("G0 X6000 Y6000\n", &sync);
		WriteToComPort("G0 X1000 Y6000\n", &sync);
		WriteToComPort("G0 X1000 Y1000\n", &sync);

		WriteToComPort("G0 X0 Y0\n", &sync);
	}

	
	sync.readport = false; // tell readportthread to shutdown

	while (sync.readthreadrunning == true) // wait till readportthread exits
	{
		Sleep(200);
	}

	CloseHandle(sync.oswriter.hEvent);
	CloseHandle(sync.serialport);	
}
vs the ethernet socket being created in this manner:

Code:
WSADATA wsaData;
struct addrinfoW *result = NULL, *ptr = NULL, hints;
struct SyncVariables
{
	OVERLAPPED oswriter;
	SOCKET ConnectSocket;
	bool readthreadrunning;
	bool controllerisconnected;
	bool readport;
};

SyncVariables sync;

sync.oswriter = {0};
sync.ConnectSocket = INVALID_SOCKET;
sync.readthreadrunning = false;
sync.controllerisconnected = false;
sync.readport = true;

if (WSAStartup(MAKEWORD(2,2), & wsaData) == 0)
{
	ZeroMemory( &hints, sizeof(hints) );
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	if (GetAddrInfo(L"192.168.2.50", L"23", &hints, &result) == 0)
	{
		for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
		{	
			sync.ConnectSocket = WSASocket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol, NULL, 0, WSA_FLAG_OVERLAPPED); 

			if (sync.ConnectSocket != INVALID_SOCKET)
			{				
				if (WSAConnect(sync.ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen, NULL, NULL, NULL, NULL) != SOCKET_ERROR)
				{					
					break;
				}
				else
				{					
					closesocket(sync.ConnectSocket);					
					sync.ConnectSocket = INVALID_SOCKET;
				}
			}
		}
						
		FreeAddrInfo(result);
	}		
		
	if (sync.ConnectSocket != INVALID_SOCKET)
	{
		sync.oswriter.hEvent = WSACreateEvent();

		_beginthread(&ReadSocketPortThread, 0, &sync);
	
		while(sync.readthreadrunning == false) // wait till we know readportthread is running before writing to port
		{
			Sleep(200);
		}

		WriteToSocketPort("IsControllerConnected\n", &sync);

		Sleep(200); // give time for readportthread to respond for this initialization

		if (sync.controllerisconnected == true)
		{
			// send g-codes to controller
			WriteToSocketPort("G0 X1000 Y1000\n", &sync);
			WriteToSocketPort("G0 X6000 Y1000\n", &sync);
			WriteToSocketPort("G0 X6000 Y6000\n", &sync);
			WriteToSocketPort("G0 X1000 Y6000\n", &sync);
			WriteToSocketPort("G0 X1000 Y1000\n", &sync);

			WriteToSocketPort("G0 X0 Y0\n", &sync);
		}

	
		sync.readport = false; // tell readportthread to shutdown

		while (sync.readthreadrunning == true) // wait till readportthread exits
		{
			Sleep(200);
		}

		WSACloseEvent(sync.oswriter.hEvent);
		closesocket(sync.ConnectSocket);
	}

	WSACleanup();
}
Secondly, here is the code for the ReadComPortThread:

Code:
struct SyncVariables
{
	OVERLAPPED oswriter;
	HANDLE serialport;
	bool readthreadrunning;
	bool controllerisconnected;
	bool readport;
};


void ReadComPortThread(void *arg)
{
	SyncVariables *sync = (SyncVariables*)arg;
	char textbuffer[256];
	OVERLAPPED osreader = {0};
	bool waitingonread = false;
	DWORD rxindex = 0;
	DWORD dwread = 0;
	char *stringindex = NULL;

	memset(textbuffer, 0, 256);
	
	osreader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);	

	sync->readthreadrunning = true;

	while(sync->readport == true)
	{
		textbuffer[0] = 0;
		dwread = 0;
		rxindex = 0;

		do
		{
			if (waitingonread == false)
			{
				if (ReadFile(sync->serialport, &textbuffer[rxindex], 1, NULL/*&dwread*/, &osreader) == FALSE)
				{		

					if (GetLastError() == ERROR_IO_PENDING)
					{
						waitingonread = true;
					}
				}
				else
				{
		
					if (GetOverlappedResult(sync->serialport, &osreader, &dwread, FALSE) == 0)
					{
						//
					}
					else
					{
						//
					}

					rxindex += dwread;
					textbuffer[rxindex] = 0;
				}
			}

			if (waitingonread == true)
			{		
				result = WaitForSingleObject(osreader.hEvent, 500);

				switch(result)
				{
				case WAIT_OBJECT_0:
		
					if (GetOverlappedResult(sync->serialport, &osreader, &dwread, FALSE) == TRUE)
					{
						waitingonread = false;
						rxindex ++;
					}
					break;
				case WAIT_TIMEOUT:
					//
					break;
				default:
					//
					break;
				}
			}

			if ((rxindex > 0) && (textbuffer[rxindex - 1] == '\n'))
				break;

		}while((dwread > 0) || (waitingonread == true));

		textbuffer[rxindex] = 0;

		if (textbuffer[0] != 0)
		{
			if ((stringindex = strstr(textbuffer, "This is a valid controller\r\n")) != 0)
			{
				sync->controllerisconnected = true;					
			}
			else if ((stringindex = strstr(textbuffer, "Some other response\r\n")) != 0)
			{
				//					
			}
			else if ((stringindex = strstr(textbuffer, "Yet even another response\r\n")) != 0)
			{
				//					
			}
		}
	}

	CloseHandle(osreader.hEvent);

	sync->readthreadrunning = false;	
}
vs the code for ReadSocketPortThread:

Code:
struct SyncVariables
{
	OVERLAPPED oswriter;
	SOCKET ConnectSocket;
	bool readthreadrunning;
	bool controllerisconnected;
	bool readport;
};


void ReadSocketPortThread(void *arg)
{
	SyncVariables *sync = (SyncVariables*)arg;
	char textbuffer[256];
	OVERLAPPED osreader = {0};
	bool waitingonread = false;
	DWORD rxindex = 0;
	DWORD dwread = 0;
	char *stringindex = NULL;

	WSABUF wsabuf;
	DWORD flags = MSG_PARTIAL;

	memset(textbuffer, 0, 256);
	
	osreader.hEvent = WSACreateEvent();	

	sync->readthreadrunning = true;

	while(sync->readport == true)
	{
		textbuffer[0] = 0;
		dwread = 0;
		rxindex = 0;

		do
		{
			if (waitingonread == false)
			{
				wsabuf.buf = &textbuffer[rxindex];
				wsabuf.len = 1;

				if (WSARecv(sync->ConnectSocket, &wsabuf, 1, &dwread, &flags, &osreader, NULL) == SOCKET_ERROR)
				{							
					if ((result = WSAGetLastError()) == WSA_IO_PENDING)
					{
						waitingonread = true;
					}
				}
				else
				{		
					if (WSAGetOverlappedResult(sync->ConnectSocket, &osreader, &dwread, FALSE, &flags) == FALSE)
					{
						//
					}
					else
					{
						//
					}

					rxindex += dwread;
					textbuffer[rxindex] = 0;
				}
			}

			if (waitingonread == true)
			{		
				result = WSAWaitForMultipleEvents(1, &osreader.hEvent, TRUE, 500, FALSE);

				switch(result)
				{
				case WSA_WAIT_EVENT_0:
		
					if (WSAGetOverlappedResult(sync->ConnectSocket, &osreader, &dwread, FALSE, &flags) == TRUE)
					{
						waitingonread = false;
						rxindex ++;
					}
					break;
				case WAIT_TIMEOUT:
					//
					break;
				default:
					//
					break;
				}
			}

			if ((rxindex > 0) && (textbuffer[rxindex - 1] == '\n'))
				break;

		}while((dwread > 0) || (waitingonread == true));

		textbuffer[rxindex] = 0;

		if (textbuffer[0] != 0)
		{
			if ((stringindex = strstr(textbuffer, "This is a valid controller\r\n")) != 0)
			{
				sync->controllerisconnected = true;					
			}
			else if ((stringindex = strstr(textbuffer, "Some other response\r\n")) != 0)
			{
				//					
			}
			else if ((stringindex = strstr(textbuffer, "Yet even another response\r\n")) != 0)
			{
				//					
			}
		}
	}

	WSACloseEvent(osreader.hEvent);

	sync->readthreadrunning = false;	
}
Lastly, the code for WriteToComPort:

Code:
void WriteToComPort(char *bufferin, SyncVariables *sync)
{
	if (sync != NULL)
	{			
		DWORD dwWritten = 0;
		DWORD result = 0;

		if (sync->serialport != NULL)
		{			
			if (WriteFile(sync->serialport, bufferin, (DWORD)strlen(bufferin), NULL/*&dwWritten*/, &sync->oswriter) == FALSE)
			{
				if (GetLastError() == ERROR_IO_PENDING)
				{
					result = WaitForSingleObject(sync->oswriter.hEvent, 100);

					switch(result)
					{
					case WAIT_OBJECT_0:
						if (GetOverlappedResult(sync->serialport, &sync->oswriter, &dwWritten, FALSE) == TRUE)
						{
							//
						}
						else
						{
							sync->readport = false;
							Sleep(250);
						}
						break;
					default:
						break;
					}
				}
				else
				{
					//
				}
			}
			else
			{
				//
			}
			
		}						
	}	
}
vs the code for WriteToSocketPort:

Code:
void WriteToSocketPort(char *bufferin, SyncVariables *sync)
{
	if (sync != NULL)
	{			
		DWORD dwWritten = 0;
		DWORD result = 0;
		WSABUF wsabuf;				
		DWORD flags;

		wsabuf.buf = bufferin;
		wsabuf.len = (ULONG)strlen(bufferin);

		if (sync->ConnectSocket != NULL)
		{			
			if (WSASend(sync->ConnectSocket, &wsabuf, 1, &dwWritten, 0, &sync->oswriter, NULL) == SOCKET_ERROR)
			{
				if (WSAGetLastError() == WSA_IO_PENDING)
				{
					result = WSAWaitForMultipleEvents(1, &sync->oswriter.hEvent, TRUE, 100, FALSE);

					switch(result)
					{
					case WSA_WAIT_EVENT_0:
						if (WSAGetOverlappedResult(sync->ConnectSocket, &sync->oswriter, &dwWritten, FALSE, &flags) == TRUE)
						{
							//
						}
						else
						{
							sync->readport = false;
							Sleep(250);
						}
						break;
					default:
						break;
					}
				}
				else
				{
					//
				}
			}
			else
			{
				//
			}
			
		}						
	}	
}
As can be seen from the above code, I am basically attempting to use the same "concept/strategy" for both COM ports and Sockets to write/read using overlapped IO.
The COM port version is working fine, with immediate responses from the read thread.
The Socket version, on the other hand, is suffering from some sluggish latency.

The three lines of code in the main thread for the COM port version:

Code:
WriteToComPort("IsControllerConnected\n", &sync);

Sleep(200); // give time for readcomportthread to respond for this initialization

if (sync.controllerisconnected == true)
...after the "IsControllerConnected" command is written to the port, while the thread rests during the following "Sleep(200)" call, the ReadComPortThread responds immediately with sync.controllerisconnected == true.

However, the corresponding three lines in the Socket version, while the thread rests during the Sleep(200) call, the ReadSocketPortThread is so sluggish that when the Sleep(200) call finishes, sync.controllerisconnected is still equal to false.

I'm pretty sure that I am doing something wrong with the Socket creation/initialization. One of the primary differences is that the COM version has these lines of code:

Code:
DCB dcb = {0};
dcb.DCBlength = sizeof(DCB);
GetCommState(sync.serialport, &dcb);
dcb.BaudRate = CBR_115200;						
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(sync.serialport, &dcb);
GetCommState(sync.serialport, &dcb);

COMMTIMEOUTS timeouts = {0};
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(sync.serialport, &timeouts);

DWORD portmask = EV_RXCHAR;
SetCommMask(sync.serialport, portmask);
....but the Socket version doesn't have any correspondning "Socket status fiddling" before going off to the races.

I'm hoping someone can spot what I am doing wrong in my socket version which is causing the overlapped io to be sluggish.