IOCP没有被触发

时间:2015-01-29 05:06:13

标签: sockets iocp

我已经编写了一个IOCP程序,我正在通过VPN进行测试。

一切正常,但服务器断开连接,客户端GetQueuedCompletionStatus没有触发异常。

我等了一天,但它并没有好转。当我换成新的VPN时,问题就解决了,我以后也没有遇到这个问题。

出了什么问题?有没有人以前见过同样的问题?

2 个答案:

答案 0 :(得分:0)

enter code here



    enter code here

#include "XYTransport.h"
//---------------------------------------------------------------------------
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
//---------------------------------------------------------------------------
#define XYTCP_LIST_CLIENT0													0
#define XYTCP_LIST_CLIENT1													1
//---------------------------------------------------------------------------
#define XYTRANSPORT_TYPE_TCP_OPEN											0
#define XYTRANSPORT_TYPE_TCP_RECV											1
#define XYTRANSPORT_TYPE_TCP_SEND											2
//---------------------------------------------------------------------------
typedef struct tagXYOVERLAPPED
{
	OVERLAPPED o;

	SOCKET s;

	UINT flags;

	WSABUF wb;
}XYOVERLAPPED, *PXYOVERLAPPED;
//---------------------------------------------------------------------------
inline LPVOID XYAlloc(HANDLE heap, UINT size)
{
	return(HeapAlloc(heap, 0, size));
}
inline VOID XYFree(HANDLE heap, LPVOID lpdata)
{
	HeapFree(heap, 0, lpdata);
}
inline PXYOVERLAPPED XYOverlappedPop(PXYTRANSPORT pt, LPBYTE buffer, SOCKET s)
{
	PXYOVERLAPPED pto = NULL;
	SOCKADDR_IN name;

	if (buffer == NULL)
	{
		buffer = (LPBYTE)VirtualAlloc(NULL, pt->bufferlength, MEM_COMMIT, PAGE_READWRITE);
	}
	if (buffer != NULL)
	{
		pto = (PXYOVERLAPPED)MALLOC(sizeof(XYOVERLAPPED));
		if (pto != NULL)
		{
			pto->wb.buf = (char *)buffer;
			pto->wb.len = pt->bufferlength;

			if (s == INVALID_SOCKET)
			{
				pto->s = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
				if (pto->s != INVALID_SOCKET)
				{
					ZeroMemory(&name, sizeof(name));
					name.sin_family = AF_INET;
					name.sin_addr.S_un.S_addr = INADDR_ANY;
					//name.sin_port = fn_htons(0);
					name.sin_port = 0;
					if (bind(pto->s, (const SOCKADDR *)&name, sizeof(name)) == 0)
					{
						if (CreateIoCompletionPort((HANDLE)pto->s, pt->hcompletion, (ULONG_PTR)pto->s, 0) == pt->hcompletion)
						{
							//
						}
					}
				}
			}
			else
			{
				pto->s = s;
			}
		}
	}

	return(pto);
}

BOOL XYTCPPushReceive(PXYTRANSPORT pt, PXYOVERLAPPED pto, SOCKET s)
{
	DWORD numberofbytes;
	DWORD flags = 0;
	BOOL result;
	int error;

	if (pto == NULL)
	{
		pto = XYOverlappedPop(pt, NULL, s);
	}

	ZeroMemory(&pto->o, sizeof(OVERLAPPED));

	pto->flags = XYTRANSPORT_TYPE_TCP_RECV;

	result = WSARecv(pto->s, &pto->wb, 1, &numberofbytes, &flags, &pto->o, NULL) != SOCKET_ERROR;
	if (!result)
	{
		error = WSAGetLastError();
		result = error == WSA_IO_PENDING;
		if (!result)
		{
			printf("WSARecv\n");
		}
	}

	return(result);
}

inline BOOL XYTCPPushSend(PXYTRANSPORT pt, PXYOVERLAPPED pto)
{
	DWORD numberofbytes;
	ULONG flags = MSG_PARTIAL;
	BOOL result;
	int error;

	ZeroMemory(&pto->o, sizeof(OVERLAPPED));

	pto->flags = XYTRANSPORT_TYPE_TCP_SEND;

	//
	pto->wb.len = 1024;
	//

	result = WSASend(pto->s, &pto->wb, 1, &numberofbytes, flags, &pto->o, NULL) != SOCKET_ERROR;
	if (!result)
	{
		error = WSAGetLastError();
		result = error == WSA_IO_PENDING;
		if (!result)
		{
			printf("Send Error\n");
		}
	}

	return(result);
}

DWORD WINAPI XYTransportWorkProc(LPVOID parameter)
{
	PXYTRANSPORT pt = (PXYTRANSPORT)parameter;
	HANDLE hcompletion = pt->hcompletion;
	LPOVERLAPPED po;
	PXYOVERLAPPED pto;
 	ULONG_PTR completionkey;
	DWORD numberofbytes;
	SOCKET s;
	BOOL flag;
	UINT type;
	UINT count;
	UINT error;

	while(pt->working)
 	{
		flag = GetQueuedCompletionStatus(hcompletion, &numberofbytes, &completionkey, &po, INFINITE);

		if (po != NULL)
		{
			pto = (PXYOVERLAPPED)CONTAINING_RECORD(po, XYOVERLAPPED, o);

			s = (SOCKET)completionkey;

			type = pto->flags;

			if (!flag)
			{
				//OutputDebugValue(_T("Except Error"), type, numberofbytes);
				printf("Except Error %d\n", type);
			}
			if (numberofbytes == 0)
			{
				//OutputDebugValue(_T("Length Error"), type);
				printf("Length Error %d\n", type);
			}

			if (!flag)
			{
				numberofbytes = 0;
			}

			switch (type)
			{
			case XYTRANSPORT_TYPE_TCP_OPEN:
				if (flag)
				{
					setsockopt(s, SOL_SOCKET, SO_UPDATE_CONNECT_CONTEXT, NULL, 0);

					XYTCPPushSend(pt, pto);
					printf("connected\n");

					if (!XYTCPPushReceive(pt, NULL, s))
					{
						//
					}
					else
					{
						printf("post recv\n");
					}
					break;
				}
				break;
			case XYTRANSPORT_TYPE_TCP_RECV:
				if (numberofbytes > 0)
				{
					XYTCPPushReceive(pt, pto, s);

					//OutputDebugString(_T("Recv"));
					printf("Recv %d\n", numberofbytes);
				}
				else
				{
					printf("Recv Error\n");
				}
				break;
			case XYTRANSPORT_TYPE_TCP_SEND:
				if (numberofbytes > 0)
				{
					XYTCPPushSend(pt, pto);
					printf("Send %d\n", numberofbytes);
				}
				else
				{
					printf("Send Except\n");
				}
				break;
			default:
				break;
			}
		}
		else
		{
			printf("Quit %d, %d", GetCurrentThreadId(), flag);

			break;
		}
 	}

	return(0);
}

VOID XYTransportStartup(PXYTRANSPORT pt, UINT pagesize)
{
	pt->hcompletion = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
	if (pt->hcompletion != INVALID_HANDLE_VALUE)
	{
		pt->lpfnConnectEx = NULL;

		pt->bufferlength = pagesize;

		pt->working = TRUE;

		pt->hthread = CreateThread(NULL, 0, XYTransportWorkProc, (LPVOID)pt, 0, NULL);
	}
}

BOOL XYTCPConnect(PXYTRANSPORT pt, const CHAR *host, USHORT port)
{
	GUID id = WSAID_CONNECTEX;
	DWORD numberofbytes = 0;
	PXYOVERLAPPED pto;
	SOCKADDR_IN name;
	BOOL result = FALSE;
	int error;

	pto = XYOverlappedPop(pt, NULL, INVALID_SOCKET);

	if (pt->lpfnConnectEx != NULL || WSAIoctl(pto->s, SIO_GET_EXTENSION_FUNCTION_POINTER, &id, sizeof(id), &pt->lpfnConnectEx, sizeof(pt->lpfnConnectEx), &numberofbytes, NULL, NULL) != SOCKET_ERROR)
	{
		ZeroMemory(&pto->o, sizeof(OVERLAPPED));

		pto->flags = XYTRANSPORT_TYPE_TCP_OPEN;

		ZeroMemory(&name, sizeof(name));
		name.sin_family = AF_INET;
		name.sin_port = htons(port);
		name.sin_addr.S_un.S_addr = inet_addr(host);
		if (name.sin_addr.S_un.S_addr != INADDR_NONE)
		{
			numberofbytes = 0;

			result = pt->lpfnConnectEx(pto->s, (SOCKADDR *)&name, sizeof(name), NULL, 0, &numberofbytes, &pto->o);
			if(!result)
			{
				error = WSAGetLastError();
				result = error == ERROR_IO_PENDING;
				if (!result)
				{
					printf("ConnectEx error\n");
				}
			}
		}
	}

	return(result);
}
//---------------------------------------------------------------------------




答案 1 :(得分:0)

客户端抛出异常是我想要的,所以我知道。

我正在使用C语言编写。在正常情况下,断开一端而另一端会触发异常,但我发现有时候需要等待很长时间,至少我等待一天以上都没有触发,有时甚至在关闭时间可以继续提供WSASend成功一段时间。