Error[8]: Undefined offset: 3144, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

文章目录



一、实验目的

  1. 掌握WinSock API I/O模型框架与原理
  2. 掌握WinSock API Select I/O模型;
  3. 掌握WinSock API WSAEventSelect I/O模型;
  4. 掌握WinSock API I/O Completion Port模型。



二、实验环境

  1. *** 作系统:WINDOWS 7及以上
  2. 开发工具:Microsoft VisualBasic6.0
  3. 实验设备:PC

三、实验内容

  1. 基于Select I/O模型创建一个回送服务器,服务器在5150端口上侦听TCP连接,并将收到的客户机数据回送客户机。


  2. 设计一个WSAEventSelect I/O模型,服务器在端口5150侦听TCP连接,回送到客户机数据。


  3. 开发一个简单的WinSock回声服务器,应用程序监听端口5150的TCP连接,并将收到的客户机数据回送给客户机。


客户机:

//程序说明:
//    这是一个回送客户机程序。


连接TCP server,发送数据,接收服务器回送的数据 // 命令行参数: // client [-p:x] [-s:IP] [-n:x] [-o] // -p:x 远程服务器端口 // -s:IP 服务器地址或主机名 // -n:x 消息的发送次数 // -o 只发送,不接收 #include "stdafx.h" #include #include #include #pragma comment(lib,"ws2_32.lib") #define DEFAULT_COUNT 20 #define DEFAULT_PORT 5050 #define DEFAULT_BUFFER 2048 #define DEFAULT_MESSAGE "\'A test message from client\'" char szServer[128], // 服务器主机名或地址 szMessage[1024]; // 发送到服务器的消息缓冲区 int iPort = DEFAULT_PORT; // 服务器端口 DWORD dwCount = DEFAULT_COUNT; // 发送消息的次数 BOOL bSendOnly = FALSE; // 只发送,不接收 // 函数用法说明 void usage() { printf("TcpClient: client [-p:x] [-s:IP] [-n:x] [-o]\n\n"); printf(" -p:x Remote port to send to\n"); printf(" -s:IP Server's IP address or hostname\n"); printf(" -n:x Number of times to send message\n"); printf(" -o Send messages only; don't receive\n"); printf("\n"); } // 命令行参数解析 void ValidateArgs(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if ((argv[i][0] == '-') || (argv[i][0] == '/')) { switch (tolower(argv[i][1])) { case 'p': if (strlen(argv[i]) > 3) iPort = atoi(&argv[i][3]); break; case 's': if (strlen(argv[i]) > 3) strcpy_s(szServer, sizeof(szServer), &argv[i][3]); break; case 'n': if (strlen(argv[i]) > 3) dwCount = atol(&argv[i][3]); break; case 'o': bSendOnly = TRUE; break; default: usage(); break; } } } } // 主线程初始化 Winsock, 分析命令行参数, 创建套接字, 连接服务器,发送和接受数据 int main(int argc, char **argv) { WSADATA wsd; SOCKET sClient; char szBuffer[DEFAULT_BUFFER]; int ret, i; struct sockaddr_in server; struct hostent *host = NULL; if (argc < 2) { usage(); exit(1); } // 分析命令行参数,加载Winsock ValidateArgs(argc, argv); if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { printf("Failed to load Winsock library! Error %d\n", WSAGetLastError()); return 1; } else printf("Winsock library loaded successfully!\n"); strcpy_s(szMessage, sizeof(szMessage), DEFAULT_MESSAGE); // 创建套接字,连接服务器 sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sClient == INVALID_SOCKET) { printf("socket() failed with error code %d\n", WSAGetLastError()); return 1; } else printf("socket() looks fine!\n"); server.sin_family = AF_INET; server.sin_port = htons(iPort); server.sin_addr.s_addr = inet_addr(szServer); if (server.sin_addr.s_addr == INADDR_NONE) { host = gethostbyname(szServer); if (host == NULL) { printf("Unable to resolve server %s\n", szServer); return 1; } else printf("The hostname resolved successfully!\n"); CopyMemory(&server.sin_addr, host->h_addr_list[0], host->h_length); } if (connect(sClient, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) { printf("connect() failed with error code %d\n", WSAGetLastError()); return 1; } else printf("connect() is pretty damn fine!\n"); // 发送和接收数据 printf("Sending and receiving data if any...\n"); for (i = 0; i < (int)dwCount; i++) { ret = send(sClient, szMessage, strlen(szMessage), 0); if (ret == 0) break; else if (ret == SOCKET_ERROR) { printf("send() failed with error code %d\n", WSAGetLastError()); break; } printf("send() should be fine. Send %d bytes\n", ret); if (!bSendOnly) { ret = recv(sClient, szBuffer, DEFAULT_BUFFER, 0); if (ret == 0) // 正常关闭 { printf("It is a graceful close!\n"); break; } else if (ret == SOCKET_ERROR) { printf("recv() failed with error code %d\n", WSAGetLastError()); break; } szBuffer[ret] = ';'printf ("recv() is OK. Received %d bytes: %s\n",, ret) szBuffer;} } if ( closesocket()sClient== 0 )printf ("closesocket() is OK!\n");else printf ("closesocket() failed with error code %d\n",WSAGetLastError ());if ( WSACleanup()== 0 )printf ("WSACleanup() is fine!\n");else printf ("WSACleanup() failed with error code %d\n",WSAGetLastError ());return 0 ;} // 程序说明:

1.Select I/O服务器
//
//    服务器在5150端口上侦听TCP连接
//    本程序演示如何基于Winsock 的 select() API I/O 模型创建一个回送服务器。


// 将收到的客户机数据再回送客户机,直到可会关闭连接 # include# include# include# pragmacomment (,lib"ws2_32.lib")# definePORT 5150 # defineDATA_BUFSIZE 8192 typedef struct _SOCKET_INFORMATION [ { CHAR Buffer]DATA_BUFSIZE;; WSABUF DataBuf; SOCKET Socket; OVERLAPPED Overlapped; DWORD BytesSEND; DWORD BytesRECV} , SOCKET_INFORMATION* ;LPSOCKET_INFORMATION// 原型 CreateSocketInformation BOOL ()SOCKET s;void FreeSocketInformation ()DWORD Index;// 全局变量 = DWORD TotalSockets 0 ;[ LPSOCKET_INFORMATION SocketArray]FD_SETSIZE;int main (int, argcchar * *)argv; { SOCKET ListenSocket; SOCKET AcceptSocket; SOCKADDR_IN InternetAddr; WSADATA wsaData; INT Ret; FD_SET WriteSet; FD_SET ReadSet; DWORD i; DWORD Total; ULONG NonBlock; DWORD Flags; DWORD SendBytes; DWORD RecvBytesif ( (=Ret WSAStartup (0x0202,& )wsaData)!= 0 )printf { ("WSAStartup() failed with error %d\n",) Ret;WSACleanup ();return 1 ;} else printf ("WSAStartup() is fine!\n");// 创建用于侦听的套接字 if ( (=ListenSocket WSASocket (,AF_INET, SOCK_STREAM0 ,NULL ,0 ,) WSA_FLAG_OVERLAPPED)== ) INVALID_SOCKETprintf { ("WSASocket() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("WSASocket() is OK!\n");. InternetAddr=sin_family ; AF_INET. InternetAddr.sin_addr=s_addr htonl ()INADDR_ANY;. InternetAddr=sin_port htons ()PORT;if ( bind(,ListenSocket( )PSOCKADDR&,InternetAddrsizeof ()InternetAddr)== ) SOCKET_ERRORprintf { ("bind() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("bind() is OK!\n");if ( listen(,ListenSocket5 ))printf { ("listen() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("listen() is OK!\n");// 将侦听套接字的阻塞模式转为非阻塞模式,这样服务器在等待连接到达期间不会发生阻塞 = NonBlock 1 ;if ( ioctlsocket(,ListenSocket, FIONBIO& )NonBlock== ) SOCKET_ERRORprintf { ("ioctlsocket() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("ioctlsocket() is OK!\n");while ( )TRUE// 初始化等待网络I/O事件通知的读写套接字集合 { FD_ZERO (&)ReadSet;FD_ZERO (&)WriteSet;// 将侦听套接字加入套接字读集合 FD_SET (,ListenSocket& )ReadSet;// 基于当前状态缓冲区为每个套接字设置读/写 // 如果缓冲区中有数据将其写入集合,否则读集 for ( =i 0 ;< i ; TotalSockets++ i)if ( [SocketArray]i[->BytesRECV > SocketArray]i)->BytesSENDFD_SET ([SocketArray]i,->Socket& )WriteSet;else FD_SET ([SocketArray]i,->Socket& )ReadSet;if ( (=Total select (0,& ,ReadSet& ,WriteSetNULL ,NULL ))== ) SOCKET_ERRORprintf { ("select() returned with error %d\n",WSAGetLastError ());return 1 ;} else printf ("select() is OK!\n");// 检查到达的连接在侦听套接字 if ( FD_ISSET(,ListenSocket& )ReadSet)-- { Total;if ( (=AcceptSocket accept (,ListenSocketNULL ,NULL ))!= ) INVALID_SOCKET// 设置套接字AcceptSocket为非阻塞模式 { // 这样服务器在调用WSASends发送数据时就不会被阻塞 = NonBlock 1 ;if ( ioctlsocket(,AcceptSocket, FIONBIO& )NonBlock== ) SOCKET_ERRORprintf { ("ioctlsocket(FIONBIO) failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("ioctlsocket(FIONBIO) is OK!\n");if ( CreateSocketInformation()AcceptSocket== ) FALSEprintf { ("CreateSocketInformation(AcceptSocket) failed!\n");return 1 ;} else printf ("CreateSocketInformation() is OK!\n");} else if { ( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf { ("accept() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("accept() is fine!\n");} } // 依次处理所有的套接字,SocketInfo为当前要处理的套接字信息 for ( =i 0 ;0 Total > && < i ; TotalSockets++ i)= { LPSOCKET_INFORMATION SocketInfo [ SocketArray]i;// 判断当前套接字的可读性,即是否有接入的连接请求或者可以接受数据 if ( FD_ISSET(,SocketInfo->Socket& )ReadSet)-- { Total;. SocketInfo->DataBuf=buf ; SocketInfo->Buffer. SocketInfo->DataBuf=len ; DATA_BUFSIZE= Flags 0 ;if ( WSARecv(,SocketInfo->Socket& ()SocketInfo->DataBuf,1 ,& ,RecvBytes& ,FlagsNULL ,NULL )== ) SOCKET_ERRORif { ( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf { ("WSARecv() failed with error %d\n",WSAGetLastError ());FreeSocketInformation ()i;} else printf ("WSARecv() is OK!\n");continue ;} else = { SocketInfo->BytesRECV ; RecvBytes// 如果接收到0个字节,则表示对方关闭连接 if ( ==RecvBytes 0 )FreeSocketInformation { ()i;continue ;} } } // 如果当前套接字在WriteSet集合中 // 则表明 if ( FD_ISSET(,SocketInfo->Socket& )WriteSet)-- { Total;. SocketInfo->DataBuf=buf + SocketInfo->Buffer ; SocketInfo->BytesSEND. SocketInfo->DataBuf=len - SocketInfo->BytesRECV ; SocketInfo->BytesSENDif ( WSASend(,SocketInfo->Socket& ()SocketInfo->DataBuf,1 ,& ,SendBytes0 ,NULL ,NULL )== ) SOCKET_ERRORif { ( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf { ("WSASend() failed with error %d\n",WSAGetLastError ());FreeSocketInformation ()i;} else printf ("WSASend() is OK!\n");continue ;} else += { SocketInfo->BytesSEND ; SendBytesif ( ==SocketInfo->BytesSEND ) SocketInfo->BytesRECV= { SocketInfo->BytesSEND 0 ;= SocketInfo->BytesRECV 0 ;} } } } } } CreateSocketInformation BOOL ()SOCKET s; { LPSOCKET_INFORMATION SIprintf ("Accepted socket number %d\n",) s;if ( (=SI ( )LPSOCKET_INFORMATIONGlobalAlloc(,GPTRsizeof ()SOCKET_INFORMATION))== NULL )printf { ("GlobalAlloc() failed with error %d\n",GetLastError ());return ; FALSE} else printf ("GlobalAlloc() for SOCKET_INFORMATION is OK!\n");// Prepare SocketInfo structure for use = SI->Socket ; s= SI->BytesSEND 0 ;= SI->BytesRECV 0 ;[ SocketArray]TotalSockets= ; SI++ TotalSockets;return ()TRUE;} void FreeSocketInformation ()DWORD Index= { LPSOCKET_INFORMATION SI [ SocketArray]Index;; DWORD iclosesocket ()SI->Socket;printf ("Closing socket number %d\n",) SI->Socket;GlobalFree ()SI;// Squash the socket array for ( =i ; Index< i ; TotalSockets++ i)[ { SocketArray]i= [ SocketArray+i 1 ];} -- TotalSockets;} // WSAEventSelect模型回送服务器

运行结果:
服务器:

客户机:

2.WSAEventSelect服务器
// WSAEventSelect.cpp
#
include# 
include# 
include# 
pragmacomment (,lib"ws2_32.lib")#
definePORT 5150 #
defineDATA_BUFSIZE 8192 typedef

struct _SOCKET_INFORMATION [ {
	CHAR Buffer]DATA_BUFSIZE;;
	WSABUF DataBuf;
	SOCKET Socket;
	DWORD BytesSEND;
	DWORD BytesRECV}
, SOCKET_INFORMATION* ;LPSOCKET_INFORMATIONCreateSocketInformation

BOOL ()SOCKET s;void
FreeSocketInformation ()DWORD Event;=

DWORD EventTotal 0 ;[
WSAEVENT EventArray]WSA_MAXIMUM_WAIT_EVENTS;[
LPSOCKET_INFORMATION SocketArray]WSA_MAXIMUM_WAIT_EVENTS;int

main (int, argcchar * *)argv;
{
	SOCKET Listen;
	SOCKET Accept;
	SOCKADDR_IN InternetAddr;
	LPSOCKET_INFORMATION SocketInfo;
	DWORD Event;
	WSANETWORKEVENTS NetworkEvents;
	WSADATA wsaData;
	DWORD Flags;
	DWORD RecvBytes;
	DWORD SendBytesif

	( WSAStartup(0x0202,& )wsaData!= 0 )printf
	{
		("WSAStartup() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("WSAStartup() is OK!\n");if

	( (=Listen socket (,AF_INET, SOCK_STREAM0 ))== ) INVALID_SOCKETprintf
	{
		("socket() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("socket() is OK!\n");if

	( CreateSocketInformation()Listen== ) FALSEprintf
		("CreateSocketInformation() failed!\n");else
	printf
		("CreateSocketInformation() is OK lol!\n");if

	( WSAEventSelect(,Listen[ EventArray-EventTotal 1 ],| FD_ACCEPT ) FD_CLOSE== ) SOCKET_ERRORprintf
	{
		("WSAEventSelect() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("WSAEventSelect() is pretty fine!\n");.

	InternetAddr=sin_family ; AF_INET.
	InternetAddr.sin_addr=s_addr htonl ()INADDR_ANY;.
	InternetAddr=sin_port htons ()PORT;if

	( bind(,Listen( )PSOCKADDR&,InternetAddrsizeof ()InternetAddr)== ) SOCKET_ERRORprintf
	{
		("bind() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("bind() is OK!\n");if

	( listen(,Listen5 ))printf
	{
		("listen() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("listen() is OK!\n");while

	( )TRUE// 等待套接字接受I/O通知
	{
		if
		( (=Event WSAWaitForMultipleEvents (,EventTotal, EventArray, FALSE, WSA_INFINITE) FALSE)== ) WSA_WAIT_FAILEDprintf
		{
			("WSAWaitForMultipleEvents() failed with error %d\n",WSAGetLastError ());return
			1 ;}
		else
		printf
			("WSAWaitForMultipleEvents() is pretty damn OK!\n");if

		( WSAEnumNetworkEvents([SocketArray-Event ] WSA_WAIT_EVENT_0,->Socket[
			EventArray-Event ] WSA_WAIT_EVENT_0,& )NetworkEvents== ) SOCKET_ERRORprintf
		{
			("WSAEnumNetworkEvents() failed with error %d\n",WSAGetLastError ());return
			1 ;}
		else
		printf
			("WSAEnumNetworkEvents() should be fine!\n");if

		( .NetworkEvents&lNetworkEvents ) FD_ACCEPTif
		{
			( .NetworkEvents[iErrorCode]FD_ACCEPT_BIT!= 0 )printf
			{
				("FD_ACCEPT failed with error %d\n",. NetworkEvents[iErrorCode]FD_ACCEPT_BIT);break
				;}
			if

			( (=Accept accept ([SocketArray-Event ] WSA_WAIT_EVENT_0,->SocketNULL ,NULL ))== ) INVALID_SOCKETprintf
			{
				("accept() failed with error %d\n",WSAGetLastError ());break
				;}
			else
			printf
				("accept() should be OK!\n");if

			( )EventTotal > WSA_MAXIMUM_WAIT_EVENTSprintf
			{
				("Too many connections - closing socket...\n");closesocket
				()Accept;break
				;}
			CreateSocketInformation

			()Accept;if

			( WSAEventSelect(,Accept[ EventArray-EventTotal 1 ],| FD_READ | FD_WRITE ) FD_CLOSE== ) SOCKET_ERRORprintf
			{
				("WSAEventSelect() failed with error %d\n",WSAGetLastError ());return
				1 ;}
			else
			printf
				("WSAEventSelect() is OK!\n");printf

			("Socket %d got connected...\n",) Accept;}
		// 如果读取和写入事件发生,试着对数据缓冲区读取和写入数据

		if
		( .NetworkEvents&lNetworkEvents || FD_READ . NetworkEvents&lNetworkEvents ) FD_WRITEif
		{
			( .NetworkEvents&lNetworkEvents && FD_READ . NetworkEvents[iErrorCode]FD_READ_BIT!= 0 )printf
			{
				("FD_READ failed with error %d\n",. NetworkEvents[iErrorCode]FD_READ_BIT);break
				;}
			else
			printf
				("FD_READ is OK!\n");if

			( .NetworkEvents&lNetworkEvents && FD_WRITE . NetworkEvents[iErrorCode]FD_WRITE_BIT!= 0 )printf
			{
				("FD_WRITE failed with error %d\n",. NetworkEvents[iErrorCode]FD_WRITE_BIT);break
				;}
			else
			printf
				("FD_WRITE is OK!\n");=

			SocketInfo [ SocketArray-Event ] WSA_WAIT_EVENT_0;// 当收到的字节数为0时读取数据

			if
			( ==SocketInfo->BytesRECV 0 ).
			{
				SocketInfo->DataBuf=buf ; SocketInfo->Buffer.
				SocketInfo->DataBuf=len ; DATA_BUFSIZE=

				Flags 0 ;if

				( WSARecv(,SocketInfo->Socket& ()SocketInfo->DataBuf,1 ,& ,RecvBytes&
					,FlagsNULL ,NULL )== ) SOCKET_ERRORif
				{
					( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf
					{
						("WSARecv() failed with error %d\n",WSAGetLastError ());FreeSocketInformation
						(-Event ) WSA_WAIT_EVENT_0;return
						1 ;}
					}
				else
				printf
				{
					("WSARecv() is working!\n");=
					SocketInfo->BytesRECV ; RecvBytes}
				}
			// 当收到的字节数大于发送的字节数时发送数据

			if
			( )SocketInfo->BytesRECV > SocketInfo->BytesSEND.
			{
				SocketInfo->DataBuf=buf + SocketInfo->Buffer ; SocketInfo->BytesSEND.
				SocketInfo->DataBuf=len - SocketInfo->BytesRECV ; SocketInfo->BytesSENDif

				( WSASend(,SocketInfo->Socket& ()SocketInfo->DataBuf,1 ,& ,SendBytes0 ,NULL
					,NULL )== ) SOCKET_ERRORif
				{
					( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf
					{
						("WSASend() failed with error %d\n",WSAGetLastError ());FreeSocketInformation
						(-Event ) WSA_WAIT_EVENT_0;return
						1 ;}
					}
				else
				printf
				{
					("WSASend() is fine! Thank you...\n");+=
					SocketInfo->BytesSEND ; SendBytesif

					( ==SocketInfo->BytesSEND ) SocketInfo->BytesRECV=
					{
						SocketInfo->BytesSEND 0 ;=
						SocketInfo->BytesRECV 0 ;}
					}
				}
			}
		if

		( .NetworkEvents&lNetworkEvents ) FD_CLOSEif
		{
			( .NetworkEvents[iErrorCode]FD_CLOSE_BIT!= 0 )printf
			{
				("FD_CLOSE failed with error %d\n",. NetworkEvents[iErrorCode]FD_CLOSE_BIT);break
				;}
			else
			printf
				("FD_CLOSE is OK!\n");printf

			("Closing socket information %d\n",[ SocketArray-Event ] WSA_WAIT_EVENT_0)->Socket;FreeSocketInformation
			(-Event ) WSA_WAIT_EVENT_0;}
		}
	return
	0 ;}
CreateSocketInformation

BOOL ()SOCKET s;
{
	LPSOCKET_INFORMATION SIif

	( ([EventArray]EventTotal= WSACreateEvent ())== ) WSA_INVALID_EVENTprintf
	{
		("WSACreateEvent() failed with error %d\n",WSAGetLastError ());return
		; FALSE}
	else
	printf
		("WSACreateEvent() is OK!\n");if

	( (=SI ( )LPSOCKET_INFORMATIONGlobalAlloc(,GPTRsizeof ()SOCKET_INFORMATION))== NULL )printf
	{
		("GlobalAlloc() failed with error %d\n",GetLastError ());return
		; FALSE}
	else
	printf
		("GlobalAlloc() for LPSOCKET_INFORMATION is OK!\n");// 准备使用SocketInfo结构

	=
	SI->Socket ; s=
	SI->BytesSEND 0 ;=
	SI->BytesRECV 0 ;[

	SocketArray]EventTotal= ; SI++
	EventTotal;return
	()TRUE;}
void

FreeSocketInformation ()DWORD Event=
{
	LPSOCKET_INFORMATION SI [ SocketArray]Event;;
	DWORD iclosesocket

	()SI->Socket;GlobalFree
	()SI;if

	( WSACloseEvent([EventArray]Event)== ) TRUEprintf
		("WSACloseEvent() is OK!\n\n");else
	printf
		("WSACloseEvent() failed miserabily!\n\n");// 将套接字和事件从数组删除

	for
	( =i ; Event< i ; EventTotal++ i)[
	{
		EventArray]i= [ EventArray+i 1 ];[
		SocketArray]i= [ SocketArray+i 1 ];}
	--

	EventTotal;}
// I/O完成端口服务器程序

运行结果:
服务器:

客户机:

3.I/O Completion Port
//程序名:IOComplete.cpp
#

include# 
include# 
include# 
pragmacomment (,lib"ws2_32.lib")#
definePORT 5150 #
defineDATA_B 8192 UFSIZE // 类型定义

typedef
struct ;
{
	OVERLAPPED Overlapped;
	WSABUF DataBuf[
	CHAR Buffer]DATA_BUFSIZE;;
	DWORD BytesSEND;
	DWORD BytesRECV}
, PER_IO_OPERATION_DATA* ;LPPER_IO_OPERATION_DATA// 结构定义

typedef
struct ;
{
	SOCKET Socket}
, PER_HANDLE_DATA* ;LPPER_HANDLE_DATA// 原型声明

ServerWorkerThread
DWORD WINAPI ()LPVOID CompletionPortID;int

main (int, argcchar * *)argv;
{
	SOCKADDR_IN InternetAddr;
	SOCKET Listen;
	HANDLE ThreadHandle;
	SOCKET Accept;
	HANDLE CompletionPort;
	SYSTEM_INFO SystemInfo;
	LPPER_HANDLE_DATA PerHandleData;
	LPPER_IO_OPERATION_DATA PerIoDataint
	; i;
	DWORD RecvBytes;
	DWORD Flags;
	DWORD ThreadID;
	WSADATA wsaData;
	DWORD Retif

	( (=Ret WSAStartup ((2,2 ),& )wsaData)!= 0 )printf
	{
		("WSAStartup() failed with error %d\n",) Ret;return
		1 ;}
	else
	printf
		("WSAStartup() is OK!\n");// 设置一个I/O完成端口

	if
	( (=CompletionPort CreateIoCompletionPort (,INVALID_HANDLE_VALUENULL ,0 ,0 ))== NULL )printf
	{
		("CreateIoCompletionPort() failed with error %d\n",GetLastError ());return
		1 ;}
	else
	printf
		("CreateIoCompletionPort() is damn OK!\n");// 测试系统中有多少CPU处理器

	GetSystemInfo
	(&)SystemInfo;// 基于系统可用的处理器创建工作线程

	// 为每个处理器创建两个线程
	for
	( =i 0 ;< i ( int).SystemInfo*dwNumberOfProcessors 2 ;++ i)// 创建一个服务器工作线程,并且传递一个完成端口给这个线程
	{
		if
		( (=ThreadHandle CreateThread (NULL,0 ,, ServerWorkerThread, CompletionPort0 ,& )ThreadID)== NULL )printf
		{
			("CreateThread() failed with error %d\n",GetLastError ());return
			1 ;}
		else
		printf
			("CreateThread() is OK!\n");// 关闭线程句柄

		CloseHandle
		()ThreadHandle;}
	// 创建服务器监听套接字

	if
	( (=Listen WSASocket (,AF_INET, SOCK_STREAM0 ,NULL ,0 ,) WSA_FLAG_OVERLAPPED)== ) INVALID_SOCKETprintf
	{
		("WSASocket() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("WSASocket() is OK!\n");.

	InternetAddr=sin_family ; AF_INET.
	InternetAddr.sin_addr=s_addr htonl ()INADDR_ANY;.
	InternetAddr=sin_port htons ()PORT;if

	( bind(,Listen( )PSOCKADDR&,InternetAddrsizeof ()InternetAddr)== ) SOCKET_ERRORprintf
	{
		("bind() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("bind() is fine!\n");// 开始监听

	if
	( listen(,Listen5 )== ) SOCKET_ERRORprintf
	{
		("listen() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("listen() is working...\n");// 接受连接并且交给完成端口处理

	while
	( )TRUEif
	{
		( (=Accept WSAAccept (,ListenNULL ,NULL ,NULL ,0 ))== ) SOCKET_ERRORprintf
		{
			("WSAAccept() failed with error %d\n",WSAGetLastError ());return
			1 ;}
		else
		printf
			("WSAAccept() looks fine!\n");// 为套接字分配内存

		if
		( (=PerHandleData ( )LPPER_HANDLE_DATAGlobalAlloc(,GPTRsizeof ()PER_HANDLE_DATA))== NULL )printf
		{
			("GlobalAlloc() failed with error %d\n",GetLastError ());return
			1 ;}
		else
		printf
			("GlobalAlloc() for LPPER_HANDLE_DATA is OK!\n");// 将套接字与完成端口关联起来

		printf
		("Socket number %d got connected...\n",) Accept;=
		PerHandleData->Socket ; Acceptif

		( CreateIoCompletionPort(()HANDLE,Accept, CompletionPort( )DWORD,PerHandleData0 )== NULL )printf
		{
			("CreateIoCompletionPort() failed with error %d\n",GetLastError ());return
			1 ;}
		else
		printf
			("CreateIoCompletionPort() is OK!\n");// 创建一个I/O套接字信息结构体,为下面调用的WSARecv函数服务

		if
		( (=PerIoData ( )LPPER_IO_OPERATION_DATAGlobalAlloc(,GPTRsizeof ()PER_IO_OPERATION_DATA))== NULL )printf
		{
			("GlobalAlloc() failed with error %d\n",GetLastError ());return
			1 ;}
		else
		printf
			("GlobalAlloc() for LPPER_IO_OPERATION_DATA is OK!\n");ZeroMemory

		(&()PerIoData->Overlapped,sizeof ()OVERLAPPED);=
		PerIoData->BytesSEND 0 ;=
		PerIoData->BytesRECV 0 ;.
		PerIoData->DataBuf=len ; DATA_BUFSIZE.
		PerIoData->DataBuf=buf ; PerIoData->Buffer=

		Flags 0 ;if
		( WSARecv(,Accept& ()PerIoData->DataBuf,1 ,& ,RecvBytes& ,Flags& ()PerIoData->Overlapped,NULL )== ) SOCKET_ERRORif
		{
			( WSAGetLastError()!= ) ERROR_IO_PENDINGprintf
			{
				("WSARecv() failed with error %d\n",WSAGetLastError ());return
				1 ;}
			}
		else
		printf
			("WSARecv() is OK!\n");}
	//end main}
ServerWorkerThread

DWORD WINAPI ()LPVOID CompletionPortID=
{
	HANDLE CompletionPort ( )HANDLE;CompletionPortID;
	DWORD BytesTransferred;
	LPPER_HANDLE_DATA PerHandleData;
	LPPER_IO_OPERATION_DATA PerIoData,
	DWORD SendBytes; RecvBytes;
	DWORD Flagswhile

	( )TRUEif
	{
		( GetQueuedCompletionStatus(,CompletionPort& ,BytesTransferred(
			)LPDWORD&,PerHandleData( *LPOVERLAPPED )&,PerIoData) INFINITE== 0 )printf
		{
			("GetQueuedCompletionStatus() failed with error %d\n",GetLastError ());return
			0 ;}
		else
		printf
			("GetQueuedCompletionStatus() is OK!\n");// 检查套接字是否发生了错误,如果发生了错误,关闭套接字并释放相关内存

		if
		( ==BytesTransferred 0 )printf
		{
			("Closing socket %d\n",) PerHandleData->Socket;if
			( closesocket()PerHandleData->Socket== ) SOCKET_ERRORprintf
			{
				("closesocket() failed with error %d\n",WSAGetLastError ());return
				0 ;}
			else
			printf
				("closesocket() is fine!\n");GlobalFree

			()PerHandleData;GlobalFree
			()PerIoData;continue
			;}
		// 如果ByteRECV字段等于0,表示一个WSARecv调用刚刚完成

		if
		( ==PerIoData->BytesRECV 0 )=
		{
			PerIoData->BytesRECV ; BytesTransferred=
			PerIoData->BytesSEND 0 ;}
			//printf("客户消息:%s\n",PerIoData->DataBuf.buf);
		else
		+=
		{
			PerIoData->BytesSEND ; BytesTransferred}
		if

		( )PerIoData->BytesRECV > PerIoData->BytesSEND// 调用WSASend()发送,直到所有收到的字节被发送
		{
			ZeroMemory
			(&()PerIoData->Overlapped,sizeof ()OVERLAPPED);.
			PerIoData->DataBuf=buf + PerIoData->Buffer ; PerIoData->BytesSEND.
			PerIoData->DataBuf=len - PerIoData->BytesRECV ; PerIoData->BytesSENDif

			( WSASend(,PerHandleData->Socket& ()PerIoData->DataBuf,1 ,& ,SendBytes0 ,&
				()PerIoData->Overlapped,NULL )== ) SOCKET_ERRORif
			{
				( WSAGetLastError()!= ) ERROR_IO_PENDINGprintf
				{
					("WSASend() failed with error %d\n",WSAGetLastError ());return
					0 ;}
				}
			else
			printf
				("WSASend() is OK!\n");}
		else
		=
		{
			PerIoData->BytesRECV 0 ;// 现在没有多余的数据可以发送,发出另外一个WSARecv()请求

			=
			Flags 0 ;ZeroMemory
			(&()PerIoData->Overlapped,sizeof ()OVERLAPPED);.
			PerIoData->DataBuf=len ; DATA_BUFSIZE.
			PerIoData->DataBuf=buf ; PerIoData->Bufferif

			( WSARecv(,PerHandleData->Socket& ()PerIoData->DataBuf,1 ,& ,RecvBytes& ,Flags&
				()PerIoData->Overlapped,NULL )== ) SOCKET_ERRORif
			{
				( WSAGetLastError()!= ) ERROR_IO_PENDINGprintf
				{
					("WSARecv() failed with error %d\n",WSAGetLastError ());return
					0 ;}
				}
			else
			printf
				("WSARecv() is OK!\n");}
		}
	}
[+++]

运行结果:
服务器:

客户机:


)
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)
【通信协议及编码】实验2:三种IO模型回送服务器程序设计_PHP_内存溢出

【通信协议及编码】实验2:三种IO模型回送服务器程序设计

【通信协议及编码】实验2:三种IO模型回送服务器程序设计,第1张

文章目录

  • 一、实验目的


  • 二、实验环境


  • 三、实验内容

    • 1.Select I/O服务器
    • 2.WSAEventSelect服务器
    • 3.I/O Completion Port



一、实验目的

  1. 掌握WinSock API I/O模型框架与原理
  2. 掌握WinSock API Select I/O模型;
  3. 掌握WinSock API WSAEventSelect I/O模型;
  4. 掌握WinSock API I/O Completion Port模型。



二、实验环境

  1. *** 作系统:WINDOWS 7及以上
  2. 开发工具:Microsoft VisualBasic6.0
  3. 实验设备:PC

三、实验内容

  1. 基于Select I/O模型创建一个回送服务器,服务器在5150端口上侦听TCP连接,并将收到的客户机数据回送客户机。


  2. 设计一个WSAEventSelect I/O模型,服务器在端口5150侦听TCP连接,回送到客户机数据。


  3. 开发一个简单的WinSock回声服务器,应用程序监听端口5150的TCP连接,并将收到的客户机数据回送给客户机。


客户机:

//程序说明:
//    这是一个回送客户机程序。


连接TCP server,发送数据,接收服务器回送的数据 // 命令行参数: // client [-p:x] [-s:IP] [-n:x] [-o] // -p:x 远程服务器端口 // -s:IP 服务器地址或主机名 // -n:x 消息的发送次数 // -o 只发送,不接收 #include "stdafx.h" #include #include #include #pragma comment(lib,"ws2_32.lib") #define DEFAULT_COUNT 20 #define DEFAULT_PORT 5050 #define DEFAULT_BUFFER 2048 #define DEFAULT_MESSAGE "\'A test message from client\'" char szServer[128], // 服务器主机名或地址 szMessage[1024]; // 发送到服务器的消息缓冲区 int iPort = DEFAULT_PORT; // 服务器端口 DWORD dwCount = DEFAULT_COUNT; // 发送消息的次数 BOOL bSendOnly = FALSE; // 只发送,不接收 // 函数用法说明 void usage() { printf("TcpClient: client [-p:x] [-s:IP] [-n:x] [-o]\n\n"); printf(" -p:x Remote port to send to\n"); printf(" -s:IP Server's IP address or hostname\n"); printf(" -n:x Number of times to send message\n"); printf(" -o Send messages only; don't receive\n"); printf("\n"); } // 命令行参数解析 void ValidateArgs(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { if ((argv[i][0] == '-') || (argv[i][0] == '/')) { switch (tolower(argv[i][1])) { case 'p': if (strlen(argv[i]) > 3) iPort = atoi(&argv[i][3]); break; case 's': if (strlen(argv[i]) > 3) strcpy_s(szServer, sizeof(szServer), &argv[i][3]); break; case 'n': if (strlen(argv[i]) > 3) dwCount = atol(&argv[i][3]); break; case 'o': bSendOnly = TRUE; break; default: usage(); break; } } } } // 主线程初始化 Winsock, 分析命令行参数, 创建套接字, 连接服务器,发送和接受数据 int main(int argc, char **argv) { WSADATA wsd; SOCKET sClient; char szBuffer[DEFAULT_BUFFER]; int ret, i; struct sockaddr_in server; struct hostent *host = NULL; if (argc < 2) { usage(); exit(1); } // 分析命令行参数,加载Winsock ValidateArgs(argc, argv); if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) { printf("Failed to load Winsock library! Error %d\n", WSAGetLastError()); return 1; } else printf("Winsock library loaded successfully!\n"); strcpy_s(szMessage, sizeof(szMessage), DEFAULT_MESSAGE); // 创建套接字,连接服务器 sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sClient == INVALID_SOCKET) { printf("socket() failed with error code %d\n", WSAGetLastError()); return 1; } else printf("socket() looks fine!\n"); server.sin_family = AF_INET; server.sin_port = htons(iPort); server.sin_addr.s_addr = inet_addr(szServer); if (server.sin_addr.s_addr == INADDR_NONE) { host = gethostbyname(szServer); if (host == NULL) { printf("Unable to resolve server %s\n", szServer); return 1; } else printf("The hostname resolved successfully!\n"); CopyMemory(&server.sin_addr, host->h_addr_list[0], host->h_length); } if (connect(sClient, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) { printf("connect() failed with error code %d\n", WSAGetLastError()); return 1; } else printf("connect() is pretty damn fine!\n"); // 发送和接收数据 printf("Sending and receiving data if any...\n"); for (i = 0; i < (int)dwCount; i++) { ret = send(sClient, szMessage, strlen(szMessage), 0); if (ret == 0) break; else if (ret == SOCKET_ERROR) { printf("send() failed with error code %d\n", WSAGetLastError()); break; } printf("send() should be fine. Send %d bytes\n", ret); if (!bSendOnly) { ret = recv(sClient, szBuffer, DEFAULT_BUFFER, 0); if (ret == 0) // 正常关闭 { printf("It is a graceful close!\n"); break; } else if (ret == SOCKET_ERROR) { printf("recv() failed with error code %d\n", WSAGetLastError()); break; } szBuffer[ret] = ';'printf ("recv() is OK. Received %d bytes: %s\n",, ret) szBuffer;} } if ( closesocket()sClient== 0 )printf ("closesocket() is OK!\n");else printf ("closesocket() failed with error code %d\n",WSAGetLastError ());if ( WSACleanup()== 0 )printf ("WSACleanup() is fine!\n");else printf ("WSACleanup() failed with error code %d\n",WSAGetLastError ());return 0 ;} // 程序说明:

1.Select I/O服务器
//
//    服务器在5150端口上侦听TCP连接
//    本程序演示如何基于Winsock 的 select() API I/O 模型创建一个回送服务器。


// 将收到的客户机数据再回送客户机,直到可会关闭连接 # include# include# include# pragmacomment (,lib"ws2_32.lib")# definePORT 5150 # defineDATA_BUFSIZE 8192 typedef struct _SOCKET_INFORMATION [ { CHAR Buffer]DATA_BUFSIZE;; WSABUF DataBuf; SOCKET Socket; OVERLAPPED Overlapped; DWORD BytesSEND; DWORD BytesRECV} , SOCKET_INFORMATION* ;LPSOCKET_INFORMATION// 原型 CreateSocketInformation BOOL ()SOCKET s;void FreeSocketInformation ()DWORD Index;// 全局变量 = DWORD TotalSockets 0 ;[ LPSOCKET_INFORMATION SocketArray]FD_SETSIZE;int main (int, argcchar * *)argv; { SOCKET ListenSocket; SOCKET AcceptSocket; SOCKADDR_IN InternetAddr; WSADATA wsaData; INT Ret; FD_SET WriteSet; FD_SET ReadSet; DWORD i; DWORD Total; ULONG NonBlock; DWORD Flags; DWORD SendBytes; DWORD RecvBytesif ( (=Ret WSAStartup (0x0202,& )wsaData)!= 0 )printf { ("WSAStartup() failed with error %d\n",) Ret;WSACleanup ();return 1 ;} else printf ("WSAStartup() is fine!\n");// 创建用于侦听的套接字 if ( (=ListenSocket WSASocket (,AF_INET, SOCK_STREAM0 ,NULL ,0 ,) WSA_FLAG_OVERLAPPED)== ) INVALID_SOCKETprintf { ("WSASocket() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("WSASocket() is OK!\n");. InternetAddr=sin_family ; AF_INET. InternetAddr.sin_addr=s_addr htonl ()INADDR_ANY;. InternetAddr=sin_port htons ()PORT;if ( bind(,ListenSocket( )PSOCKADDR&,InternetAddrsizeof ()InternetAddr)== ) SOCKET_ERRORprintf { ("bind() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("bind() is OK!\n");if ( listen(,ListenSocket5 ))printf { ("listen() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("listen() is OK!\n");// 将侦听套接字的阻塞模式转为非阻塞模式,这样服务器在等待连接到达期间不会发生阻塞 = NonBlock 1 ;if ( ioctlsocket(,ListenSocket, FIONBIO& )NonBlock== ) SOCKET_ERRORprintf { ("ioctlsocket() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("ioctlsocket() is OK!\n");while ( )TRUE// 初始化等待网络I/O事件通知的读写套接字集合 { FD_ZERO (&)ReadSet;FD_ZERO (&)WriteSet;// 将侦听套接字加入套接字读集合 FD_SET (,ListenSocket& )ReadSet;// 基于当前状态缓冲区为每个套接字设置读/写 // 如果缓冲区中有数据将其写入集合,否则读集 for ( =i 0 ;< i ; TotalSockets++ i)if ( [SocketArray]i[->BytesRECV > SocketArray]i)->BytesSENDFD_SET ([SocketArray]i,->Socket& )WriteSet;else FD_SET ([SocketArray]i,->Socket& )ReadSet;if ( (=Total select (0,& ,ReadSet& ,WriteSetNULL ,NULL ))== ) SOCKET_ERRORprintf { ("select() returned with error %d\n",WSAGetLastError ());return 1 ;} else printf ("select() is OK!\n");// 检查到达的连接在侦听套接字 if ( FD_ISSET(,ListenSocket& )ReadSet)-- { Total;if ( (=AcceptSocket accept (,ListenSocketNULL ,NULL ))!= ) INVALID_SOCKET// 设置套接字AcceptSocket为非阻塞模式 { // 这样服务器在调用WSASends发送数据时就不会被阻塞 = NonBlock 1 ;if ( ioctlsocket(,AcceptSocket, FIONBIO& )NonBlock== ) SOCKET_ERRORprintf { ("ioctlsocket(FIONBIO) failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("ioctlsocket(FIONBIO) is OK!\n");if ( CreateSocketInformation()AcceptSocket== ) FALSEprintf { ("CreateSocketInformation(AcceptSocket) failed!\n");return 1 ;} else printf ("CreateSocketInformation() is OK!\n");} else if { ( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf { ("accept() failed with error %d\n",WSAGetLastError ());return 1 ;} else printf ("accept() is fine!\n");} } // 依次处理所有的套接字,SocketInfo为当前要处理的套接字信息 for ( =i 0 ;0 Total > && < i ; TotalSockets++ i)= { LPSOCKET_INFORMATION SocketInfo [ SocketArray]i;// 判断当前套接字的可读性,即是否有接入的连接请求或者可以接受数据 if ( FD_ISSET(,SocketInfo->Socket& )ReadSet)-- { Total;. SocketInfo->DataBuf=buf ; SocketInfo->Buffer. SocketInfo->DataBuf=len ; DATA_BUFSIZE= Flags 0 ;if ( WSARecv(,SocketInfo->Socket& ()SocketInfo->DataBuf,1 ,& ,RecvBytes& ,FlagsNULL ,NULL )== ) SOCKET_ERRORif { ( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf { ("WSARecv() failed with error %d\n",WSAGetLastError ());FreeSocketInformation ()i;} else printf ("WSARecv() is OK!\n");continue ;} else = { SocketInfo->BytesRECV ; RecvBytes// 如果接收到0个字节,则表示对方关闭连接 if ( ==RecvBytes 0 )FreeSocketInformation { ()i;continue ;} } } // 如果当前套接字在WriteSet集合中 // 则表明 if ( FD_ISSET(,SocketInfo->Socket& )WriteSet)-- { Total;. SocketInfo->DataBuf=buf + SocketInfo->Buffer ; SocketInfo->BytesSEND. SocketInfo->DataBuf=len - SocketInfo->BytesRECV ; SocketInfo->BytesSENDif ( WSASend(,SocketInfo->Socket& ()SocketInfo->DataBuf,1 ,& ,SendBytes0 ,NULL ,NULL )== ) SOCKET_ERRORif { ( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf { ("WSASend() failed with error %d\n",WSAGetLastError ());FreeSocketInformation ()i;} else printf ("WSASend() is OK!\n");continue ;} else += { SocketInfo->BytesSEND ; SendBytesif ( ==SocketInfo->BytesSEND ) SocketInfo->BytesRECV= { SocketInfo->BytesSEND 0 ;= SocketInfo->BytesRECV 0 ;} } } } } } CreateSocketInformation BOOL ()SOCKET s; { LPSOCKET_INFORMATION SIprintf ("Accepted socket number %d\n",) s;if ( (=SI ( )LPSOCKET_INFORMATIONGlobalAlloc(,GPTRsizeof ()SOCKET_INFORMATION))== NULL )printf { ("GlobalAlloc() failed with error %d\n",GetLastError ());return ; FALSE} else printf ("GlobalAlloc() for SOCKET_INFORMATION is OK!\n");// Prepare SocketInfo structure for use = SI->Socket ; s= SI->BytesSEND 0 ;= SI->BytesRECV 0 ;[ SocketArray]TotalSockets= ; SI++ TotalSockets;return ()TRUE;} void FreeSocketInformation ()DWORD Index= { LPSOCKET_INFORMATION SI [ SocketArray]Index;; DWORD iclosesocket ()SI->Socket;printf ("Closing socket number %d\n",) SI->Socket;GlobalFree ()SI;// Squash the socket array for ( =i ; Index< i ; TotalSockets++ i)[ { SocketArray]i= [ SocketArray+i 1 ];} -- TotalSockets;} // WSAEventSelect模型回送服务器

运行结果:
服务器:

客户机:

2.WSAEventSelect服务器
// WSAEventSelect.cpp
#
include# 
include# 
include# 
pragmacomment (,lib"ws2_32.lib")#
definePORT 5150 #
defineDATA_BUFSIZE 8192 typedef

struct _SOCKET_INFORMATION [ {
	CHAR Buffer]DATA_BUFSIZE;;
	WSABUF DataBuf;
	SOCKET Socket;
	DWORD BytesSEND;
	DWORD BytesRECV}
, SOCKET_INFORMATION* ;LPSOCKET_INFORMATIONCreateSocketInformation

BOOL ()SOCKET s;void
FreeSocketInformation ()DWORD Event;=

DWORD EventTotal 0 ;[
WSAEVENT EventArray]WSA_MAXIMUM_WAIT_EVENTS;[
LPSOCKET_INFORMATION SocketArray]WSA_MAXIMUM_WAIT_EVENTS;int

main (int, argcchar * *)argv;
{
	SOCKET Listen;
	SOCKET Accept;
	SOCKADDR_IN InternetAddr;
	LPSOCKET_INFORMATION SocketInfo;
	DWORD Event;
	WSANETWORKEVENTS NetworkEvents;
	WSADATA wsaData;
	DWORD Flags;
	DWORD RecvBytes;
	DWORD SendBytesif

	( WSAStartup(0x0202,& )wsaData!= 0 )printf
	{
		("WSAStartup() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("WSAStartup() is OK!\n");if

	( (=Listen socket (,AF_INET, SOCK_STREAM0 ))== ) INVALID_SOCKETprintf
	{
		("socket() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("socket() is OK!\n");if

	( CreateSocketInformation()Listen== ) FALSEprintf
		("CreateSocketInformation() failed!\n");else
	printf
		("CreateSocketInformation() is OK lol!\n");if

	( WSAEventSelect(,Listen[ EventArray-EventTotal 1 ],| FD_ACCEPT ) FD_CLOSE== ) SOCKET_ERRORprintf
	{
		("WSAEventSelect() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("WSAEventSelect() is pretty fine!\n");.

	InternetAddr=sin_family ; AF_INET.
	InternetAddr.sin_addr=s_addr htonl ()INADDR_ANY;.
	InternetAddr=sin_port htons ()PORT;if

	( bind(,Listen( )PSOCKADDR&,InternetAddrsizeof ()InternetAddr)== ) SOCKET_ERRORprintf
	{
		("bind() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("bind() is OK!\n");if

	( listen(,Listen5 ))printf
	{
		("listen() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("listen() is OK!\n");while

	( )TRUE// 等待套接字接受I/O通知
	{
		if
		( (=Event WSAWaitForMultipleEvents (,EventTotal, EventArray, FALSE, WSA_INFINITE) FALSE)== ) WSA_WAIT_FAILEDprintf
		{
			("WSAWaitForMultipleEvents() failed with error %d\n",WSAGetLastError ());return
			1 ;}
		else
		printf
			("WSAWaitForMultipleEvents() is pretty damn OK!\n");if

		( WSAEnumNetworkEvents([SocketArray-Event ] WSA_WAIT_EVENT_0,->Socket[
			EventArray-Event ] WSA_WAIT_EVENT_0,& )NetworkEvents== ) SOCKET_ERRORprintf
		{
			("WSAEnumNetworkEvents() failed with error %d\n",WSAGetLastError ());return
			1 ;}
		else
		printf
			("WSAEnumNetworkEvents() should be fine!\n");if

		( .NetworkEvents&lNetworkEvents ) FD_ACCEPTif
		{
			( .NetworkEvents[iErrorCode]FD_ACCEPT_BIT!= 0 )printf
			{
				("FD_ACCEPT failed with error %d\n",. NetworkEvents[iErrorCode]FD_ACCEPT_BIT);break
				;}
			if

			( (=Accept accept ([SocketArray-Event ] WSA_WAIT_EVENT_0,->SocketNULL ,NULL ))== ) INVALID_SOCKETprintf
			{
				("accept() failed with error %d\n",WSAGetLastError ());break
				;}
			else
			printf
				("accept() should be OK!\n");if

			( )EventTotal > WSA_MAXIMUM_WAIT_EVENTSprintf
			{
				("Too many connections - closing socket...\n");closesocket
				()Accept;break
				;}
			CreateSocketInformation

			()Accept;if

			( WSAEventSelect(,Accept[ EventArray-EventTotal 1 ],| FD_READ | FD_WRITE ) FD_CLOSE== ) SOCKET_ERRORprintf
			{
				("WSAEventSelect() failed with error %d\n",WSAGetLastError ());return
				1 ;}
			else
			printf
				("WSAEventSelect() is OK!\n");printf

			("Socket %d got connected...\n",) Accept;}
		// 如果读取和写入事件发生,试着对数据缓冲区读取和写入数据

		if
		( .NetworkEvents&lNetworkEvents || FD_READ . NetworkEvents&lNetworkEvents ) FD_WRITEif
		{
			( .NetworkEvents&lNetworkEvents && FD_READ . NetworkEvents[iErrorCode]FD_READ_BIT!= 0 )printf
			{
				("FD_READ failed with error %d\n",. NetworkEvents[iErrorCode]FD_READ_BIT);break
				;}
			else
			printf
				("FD_READ is OK!\n");if

			( .NetworkEvents&lNetworkEvents && FD_WRITE . NetworkEvents[iErrorCode]FD_WRITE_BIT!= 0 )printf
			{
				("FD_WRITE failed with error %d\n",. NetworkEvents[iErrorCode]FD_WRITE_BIT);break
				;}
			else
			printf
				("FD_WRITE is OK!\n");=

			SocketInfo [ SocketArray-Event ] WSA_WAIT_EVENT_0;// 当收到的字节数为0时读取数据

			if
			( ==SocketInfo->BytesRECV 0 ).
			{
				SocketInfo->DataBuf=buf ; SocketInfo->Buffer.
				SocketInfo->DataBuf=len ; DATA_BUFSIZE=

				Flags 0 ;if

				( WSARecv(,SocketInfo->Socket& ()SocketInfo->DataBuf,1 ,& ,RecvBytes&
					,FlagsNULL ,NULL )== ) SOCKET_ERRORif
				{
					( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf
					{
						("WSARecv() failed with error %d\n",WSAGetLastError ());FreeSocketInformation
						(-Event ) WSA_WAIT_EVENT_0;return
						1 ;}
					}
				else
				printf
				{
					("WSARecv() is working!\n");=
					SocketInfo->BytesRECV ; RecvBytes}
				}
			// 当收到的字节数大于发送的字节数时发送数据

			if
			( )SocketInfo->BytesRECV > SocketInfo->BytesSEND.
			{
				SocketInfo->DataBuf=buf + SocketInfo->Buffer ; SocketInfo->BytesSEND.
				SocketInfo->DataBuf=len - SocketInfo->BytesRECV ; SocketInfo->BytesSENDif

				( WSASend(,SocketInfo->Socket& ()SocketInfo->DataBuf,1 ,& ,SendBytes0 ,NULL
					,NULL )== ) SOCKET_ERRORif
				{
					( WSAGetLastError()!= ) WSAEWOULDBLOCKprintf
					{
						("WSASend() failed with error %d\n",WSAGetLastError ());FreeSocketInformation
						(-Event ) WSA_WAIT_EVENT_0;return
						1 ;}
					}
				else
				printf
				{
					("WSASend() is fine! Thank you...\n");+=
					SocketInfo->BytesSEND ; SendBytesif

					( ==SocketInfo->BytesSEND ) SocketInfo->BytesRECV=
					{
						SocketInfo->BytesSEND 0 ;=
						SocketInfo->BytesRECV 0 ;}
					}
				}
			}
		if

		( .NetworkEvents&lNetworkEvents ) FD_CLOSEif
		{
			( .NetworkEvents[iErrorCode]FD_CLOSE_BIT!= 0 )printf
			{
				("FD_CLOSE failed with error %d\n",. NetworkEvents[iErrorCode]FD_CLOSE_BIT);break
				;}
			else
			printf
				("FD_CLOSE is OK!\n");printf

			("Closing socket information %d\n",[ SocketArray-Event ] WSA_WAIT_EVENT_0)->Socket;FreeSocketInformation
			(-Event ) WSA_WAIT_EVENT_0;}
		}
	return
	0 ;}
CreateSocketInformation

BOOL ()SOCKET s;
{
	LPSOCKET_INFORMATION SIif

	( ([EventArray]EventTotal= WSACreateEvent ())== ) WSA_INVALID_EVENTprintf
	{
		("WSACreateEvent() failed with error %d\n",WSAGetLastError ());return
		; FALSE}
	else
	printf
		("WSACreateEvent() is OK!\n");if

	( (=SI ( )LPSOCKET_INFORMATIONGlobalAlloc(,GPTRsizeof ()SOCKET_INFORMATION))== NULL )printf
	{
		("GlobalAlloc() failed with error %d\n",GetLastError ());return
		; FALSE}
	else
	printf
		("GlobalAlloc() for LPSOCKET_INFORMATION is OK!\n");// 准备使用SocketInfo结构

	=
	SI->Socket ; s=
	SI->BytesSEND 0 ;=
	SI->BytesRECV 0 ;[

	SocketArray]EventTotal= ; SI++
	EventTotal;return
	()TRUE;}
void

FreeSocketInformation ()DWORD Event=
{
	LPSOCKET_INFORMATION SI [ SocketArray]Event;;
	DWORD iclosesocket

	()SI->Socket;GlobalFree
	()SI;if

	( WSACloseEvent([EventArray]Event)== ) TRUEprintf
		("WSACloseEvent() is OK!\n\n");else
	printf
		("WSACloseEvent() failed miserabily!\n\n");// 将套接字和事件从数组删除

	for
	( =i ; Event< i ; EventTotal++ i)[
	{
		EventArray]i= [ EventArray+i 1 ];[
		SocketArray]i= [ SocketArray+i 1 ];}
	--

	EventTotal;}
// I/O完成端口服务器程序

运行结果:
服务器:

客户机:

3.I/O Completion Port
//程序名:IOComplete.cpp
#

include# 
include# 
include# 
pragmacomment (,lib"ws2_32.lib")#
definePORT 5150 #
defineDATA_B 8192 UFSIZE // 类型定义

typedef
struct ;
{
	OVERLAPPED Overlapped;
	WSABUF DataBuf[
	CHAR Buffer]DATA_BUFSIZE;;
	DWORD BytesSEND;
	DWORD BytesRECV}
, PER_IO_OPERATION_DATA* ;LPPER_IO_OPERATION_DATA// 结构定义

typedef
struct ;
{
	SOCKET Socket}
, PER_HANDLE_DATA* ;LPPER_HANDLE_DATA// 原型声明

ServerWorkerThread
DWORD WINAPI ()LPVOID CompletionPortID;int

main (int, argcchar * *)argv;
{
	SOCKADDR_IN InternetAddr;
	SOCKET Listen;
	HANDLE ThreadHandle;
	SOCKET Accept;
	HANDLE CompletionPort;
	SYSTEM_INFO SystemInfo;
	LPPER_HANDLE_DATA PerHandleData;
	LPPER_IO_OPERATION_DATA PerIoDataint
	; i;
	DWORD RecvBytes;
	DWORD Flags;
	DWORD ThreadID;
	WSADATA wsaData;
	DWORD Retif

	( (=Ret WSAStartup ((2,2 ),& )wsaData)!= 0 )printf
	{
		("WSAStartup() failed with error %d\n",) Ret;return
		1 ;}
	else
	printf
		("WSAStartup() is OK!\n");// 设置一个I/O完成端口

	if
	( (=CompletionPort CreateIoCompletionPort (,INVALID_HANDLE_VALUENULL ,0 ,0 ))== NULL )printf
	{
		("CreateIoCompletionPort() failed with error %d\n",GetLastError ());return
		1 ;}
	else
	printf
		("CreateIoCompletionPort() is damn OK!\n");// 测试系统中有多少CPU处理器

	GetSystemInfo
	(&)SystemInfo;// 基于系统可用的处理器创建工作线程

	// 为每个处理器创建两个线程
	for
	( =i 0 ;< i ( int).SystemInfo*dwNumberOfProcessors 2 ;++ i)// 创建一个服务器工作线程,并且传递一个完成端口给这个线程
	{
		if
		( (=ThreadHandle CreateThread (NULL,0 ,, ServerWorkerThread, CompletionPort0 ,& )ThreadID)== NULL )printf
		{
			("CreateThread() failed with error %d\n",GetLastError ());return
			1 ;}
		else
		printf
			("CreateThread() is OK!\n");// 关闭线程句柄

		CloseHandle
		()ThreadHandle;}
	// 创建服务器监听套接字

	if
	( (=Listen WSASocket (,AF_INET, SOCK_STREAM0 ,NULL ,0 ,) WSA_FLAG_OVERLAPPED)== ) INVALID_SOCKETprintf
	{
		("WSASocket() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("WSASocket() is OK!\n");.

	InternetAddr=sin_family ; AF_INET.
	InternetAddr.sin_addr=s_addr htonl ()INADDR_ANY;.
	InternetAddr=sin_port htons ()PORT;if

	( bind(,Listen( )PSOCKADDR&,InternetAddrsizeof ()InternetAddr)== ) SOCKET_ERRORprintf
	{
		("bind() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("bind() is fine!\n");// 开始监听

	if
	( listen(,Listen5 )== ) SOCKET_ERRORprintf
	{
		("listen() failed with error %d\n",WSAGetLastError ());return
		1 ;}
	else
	printf
		("listen() is working...\n");// 接受连接并且交给完成端口处理

	while
	( )TRUEif
	{
		( (=Accept WSAAccept (,ListenNULL ,NULL ,NULL ,0 ))== ) SOCKET_ERRORprintf
		{
			("WSAAccept() failed with error %d\n",WSAGetLastError ());return
			1 ;}
		else
		printf
			("WSAAccept() looks fine!\n");// 为套接字分配内存

		if
		( (=PerHandleData ( )LPPER_HANDLE_DATAGlobalAlloc(,GPTRsizeof ()PER_HANDLE_DATA))== NULL )printf
		{
			("GlobalAlloc() failed with error %d\n",GetLastError ());return
			1 ;}
		else
		printf
			("GlobalAlloc() for LPPER_HANDLE_DATA is OK!\n");// 将套接字与完成端口关联起来

		printf
		("Socket number %d got connected...\n",) Accept;=
		PerHandleData->Socket ; Acceptif

		( CreateIoCompletionPort(()HANDLE,Accept, CompletionPort( )DWORD,PerHandleData0 )== NULL )printf
		{
			("CreateIoCompletionPort() failed with error %d\n",GetLastError ());return
			1 ;}
		else
		printf
			("CreateIoCompletionPort() is OK!\n");// 创建一个I/O套接字信息结构体,为下面调用的WSARecv函数服务

		if
		( (=PerIoData ( )LPPER_IO_OPERATION_DATAGlobalAlloc(,GPTRsizeof ()PER_IO_OPERATION_DATA))== NULL )printf
		{
			("GlobalAlloc() failed with error %d\n",GetLastError ());return
			1 ;}
		else
		printf
			("GlobalAlloc() for LPPER_IO_OPERATION_DATA is OK!\n");ZeroMemory

		(&()PerIoData->Overlapped,sizeof ()OVERLAPPED);=
		PerIoData->BytesSEND 0 ;=
		PerIoData->BytesRECV 0 ;.
		PerIoData->DataBuf=len ; DATA_BUFSIZE.
		PerIoData->DataBuf=buf ; PerIoData->Buffer=

		Flags 0 ;if
		( WSARecv(,Accept& ()PerIoData->DataBuf,1 ,& ,RecvBytes& ,Flags& ()PerIoData->Overlapped,NULL )== ) SOCKET_ERRORif
		{
			( WSAGetLastError()!= ) ERROR_IO_PENDINGprintf
			{
				("WSARecv() failed with error %d\n",WSAGetLastError ());return
				1 ;}
			}
		else
		printf
			("WSARecv() is OK!\n");}
	//end main}
ServerWorkerThread

DWORD WINAPI ()LPVOID CompletionPortID=
{
	HANDLE CompletionPort ( )HANDLE;CompletionPortID;
	DWORD BytesTransferred;
	LPPER_HANDLE_DATA PerHandleData;
	LPPER_IO_OPERATION_DATA PerIoData,
	DWORD SendBytes; RecvBytes;
	DWORD Flagswhile

	( )TRUEif
	{
		( GetQueuedCompletionStatus(,CompletionPort& ,BytesTransferred(
			)LPDWORD&,PerHandleData( *LPOVERLAPPED )&,PerIoData) INFINITE== 0 )printf
		{
			("GetQueuedCompletionStatus() failed with error %d\n",GetLastError ());return
			0 ;}
		else
		printf
			("GetQueuedCompletionStatus() is OK!\n");// 检查套接字是否发生了错误,如果发生了错误,关闭套接字并释放相关内存

		if
		( ==BytesTransferred 0 )printf
		{
			("Closing socket %d\n",) PerHandleData->Socket;if
			( closesocket()PerHandleData->Socket== ) SOCKET_ERRORprintf
			{
				("closesocket() failed with error %d\n",WSAGetLastError ());return
				0 ;}
			else
			printf
				("closesocket() is fine!\n");GlobalFree

			()PerHandleData;GlobalFree
			()PerIoData;continue
			;}
		// 如果ByteRECV字段等于0,表示一个WSARecv调用刚刚完成

		if
		( ==PerIoData->BytesRECV 0 )=
		{
			PerIoData->BytesRECV ; BytesTransferred=
			PerIoData->BytesSEND 0 ;}
			//printf("客户消息:%s\n",PerIoData->DataBuf.buf);
		else
		+=
		{
			PerIoData->BytesSEND ; BytesTransferred}
		if

		( )PerIoData->BytesRECV > PerIoData->BytesSEND// 调用WSASend()发送,直到所有收到的字节被发送
		{
			ZeroMemory
			(&()PerIoData->Overlapped,sizeof ()OVERLAPPED);.
			PerIoData->DataBuf=buf + PerIoData->Buffer ; PerIoData->BytesSEND.
			PerIoData->DataBuf=len - PerIoData->BytesRECV ; PerIoData->BytesSENDif

			( WSASend(,PerHandleData->Socket& ()PerIoData->DataBuf,1 ,& ,SendBytes0 ,&
				()PerIoData->Overlapped,NULL )== ) SOCKET_ERRORif
			{
				( WSAGetLastError()!= ) ERROR_IO_PENDINGprintf
				{
					("WSASend() failed with error %d\n",WSAGetLastError ());return
					0 ;}
				}
			else
			printf
				("WSASend() is OK!\n");}
		else
		=
		{
			PerIoData->BytesRECV 0 ;// 现在没有多余的数据可以发送,发出另外一个WSARecv()请求

			=
			Flags 0 ;ZeroMemory
			(&()PerIoData->Overlapped,sizeof ()OVERLAPPED);.
			PerIoData->DataBuf=len ; DATA_BUFSIZE.
			PerIoData->DataBuf=buf ; PerIoData->Bufferif

			( WSARecv(,PerHandleData->Socket& ()PerIoData->DataBuf,1 ,& ,RecvBytes& ,Flags&
				()PerIoData->Overlapped,NULL )== ) SOCKET_ERRORif
			{
				( WSAGetLastError()!= ) ERROR_IO_PENDINGprintf
				{
					("WSARecv() failed with error %d\n",WSAGetLastError ());return
					0 ;}
				}
			else
			printf
				("WSARecv() is OK!\n");}
		}
	}

运行结果:
服务器:

客户机:


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/563665.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)

保存