网络编程——其他套接字I/O模型编程

目的

(1) 掌握Windows下异步通知I/O模型编程方法;
(2) 掌握Windows下重叠I/O模型编程方法;
(3) 掌握Windows下完成端口模型编程方法;

内容

(1) 使用异步通知I/O模型实现回声服务器端(及客户端);
(2) 使用异步通知I/O模型编写聊天服务器端(及客户端);
(3) 使用重叠I/O模型实现回声服务器端(及客户端);
(4) 使用重叠I/O模型编写聊天服务器端(及客户端);
(5) 使用完成端口模型实现回声服务器端(及客户端);
(6) 使用完成端口模型编写聊天服务器端(及客户端)。

源代码及结果

(1) 使用异步通知I/O模型实现回声服务器端(及客户端);

//服务端:
#include <stdio.h>
#include <string.h>
#include <winsock2.h>

#define BUF_SIZE 100

void CompressSockets(SOCKET hSockArr[], int idx, int total);
void CompressEvents(WSAEVENT hEventArr[], int idx, int total);
void ErrorHandling(char* msg);

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET hServSock, hClntSock;
	SOCKADDR_IN servAdr, clntAdr;

	SOCKET hSockArr[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT hEventArr[WSA_MAXIMUM_WAIT_EVENTS];
	WSAEVENT newEvent;
	WSANETWORKEVENTS netEvents;

	int numOfClntSock = 0;
	int strLen, i;
	int posInfo, startIdx;
	int clntAdrLen;
	char msg[BUF_SIZE];

	if (argc != 2) {
		printf("Usage: %s <port>\n", argv[0]);
		exit(1);
	}
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	hServSock = socket(PF_INET, SOCK_STREAM, 0);
	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = htonl(INADDR_ANY);
	servAdr.sin_port = htons(atoi(argv[1]));

	if (bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
		ErrorHandling("bind() error");

	if (listen(hServSock, 5) == SOCKET_ERROR)
		ErrorHandling("listen() error");

	newEvent = WSACreateEvent();
	if (WSAEventSelect(hServSock, newEvent, FD_ACCEPT) == SOCKET_ERROR)
		ErrorHandling("WSAEventSelect() error");

	hSockArr[numOfClntSock] = hServSock;
	hEventArr[numOfClntSock] = newEvent;
	numOfClntSock++;

	while (1)
	{
		posInfo = WSAWaitForMultipleEvents(
			numOfClntSock, hEventArr, FALSE, WSA_INFINITE, FALSE);
		startIdx = posInfo - WSA_WAIT_EVENT_0;

		for (i = startIdx; i < numOfClntSock; i++)
		{
			int sigEventIdx =
				WSAWaitForMultipleEvents(1, &hEventArr[i], TRUE, 0, FALSE);
			if ((sigEventIdx == WSA_WAIT_FAILED || sigEventIdx == WSA_WAIT_TIMEOUT))
			{
				continue;
			}
			else
			{
				sigEventIdx = i;
				WSAEnumNetworkEvents(
					hSockArr[sigEventIdx], hEventArr[sigEventIdx], &netEvents);
				if (netEvents.lNetworkEvents & FD_ACCEPT)
				{
					if (netEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
					{
						puts("Accept Error");
						break;
					}
					clntAdrLen = sizeof(clntAdr);
					hClntSock = accept(
						hSockArr[sigEventIdx], (SOCKADDR*)&clntAdr, &clntAdrLen);
					newEvent = WSACreateEvent();
					WSAEventSelect(hClntSock, newEvent, FD_READ | FD_CLOSE);

					hEventArr[numOfClntSock] = newEvent;
					hSockArr[numOfClntSock] = hClntSock;
					numOfClntSock++;
					puts("connected new client...");
				}

				if (netEvents.lNetworkEvents & FD_READ)
				{
					if (netEvents.iErrorCode[FD_READ_BIT] != 0)
					{
						puts("Read Error");
						break;
					}
					strLen = recv(hSockArr[sigEventIdx], msg, sizeof(msg), 0);
					send(hSockArr[sigEventIdx], msg, strLen, 0);
				}

				if (netEvents.lNetworkEvents & FD_CLOSE)
				{
					if (netEvents.iErrorCode[FD_CLOSE_BIT] != 0)
					{
						puts("Close Error");
						break;
					}
					WSACloseEvent(hEventArr[sigEventIdx]);
					closesocket(hSockArr[sigEventIdx]);

					numOfClntSock--;
					CompressSockets(hSockArr, sigEventIdx, numOfClntSock);
					CompressEvents(hEventArr, sigEventIdx, numOfClntSock);
				}
			}
		}
	}
	WSACleanup();
	return 0;
}

void CompressSockets(SOCKET hSockArr[], int idx, int total)
{
	int i;
	for (i = idx; i < total; i++)
		hSockArr[i] = hSockArr[i + 1];
}
void CompressEvents(WSAEVENT hEventArr[], int idx, int total)
{
	int i;
	for (i = idx; i < total; i++)
		hEventArr[i] = hEventArr[i + 1];
}
void ErrorHandling(char* msg)
{
	fputs(msg, stderr);
	fputc('\n', stderr);
	exit(1);
}
//客户端:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <winsock2.h>

#define BUF_SIZE 1024
void ErrorHandling(char* message);

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET hSocket;
	char message[BUF_SIZE];
	int strLen;
	SOCKADDR_IN servAdr;

	if (argc != 3) {
		printf("Usage : %s <IP> <port>\n", argv[0]);
		exit(1);
	}

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	hSocket = socket(PF_INET, SOCK_STREAM, 0);
	if (hSocket == INVALID_SOCKET)
		ErrorHandling("socket() error");

	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = inet_addr(argv[1]);
	servAdr.sin_port = htons(atoi(argv[2]));

	if (connect(hSocket, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
		ErrorHandling("connect() error!");
	else
		puts("Connected...........");

	while (1)
	{
		fputs("Input message(Q to quit): ", stdout);
		fgets(message, BUF_SIZE, stdin);

		if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
			break;

		send(hSocket, message, strlen(message), 0);
		strLen = recv(hSocket, message, BUF_SIZE - 1, 0);
		message[strLen] = 0;
		printf("Message from server: %s", message);
	}

	closesocket(hSocket);
	WSACleanup();
	return 0;
}

void ErrorHandling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

测试结果:
在这里插入图片描述
在这里插入图片描述

(2) 使用异步通知I/O模型编写聊天服务器端(及客户端);

//思路:借助实验六中聊天服务端的思路,实现一对一及群聊功能。
//服务端:
// ChatServ_win.cpp
#include <stdio.h>
#include <string.h>
#include <winsock2.h>

#define BUF_SIZE 100

void Compress(SOCKET hSockArr[], char hSockname[WSA_MAXIMUM_WAIT_EVENTS][BUFSIZ], WSAEVENT hEventArr[], SOCKET hSockTarget[], int idx, int total);
void ErrorHandling(char* msg);

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET hServSock, hClntSock;
	SOCKADDR_IN servAdr, clntAdr;

	SOCKET hSockArr[WSA_MAXIMUM_WAIT_EVENTS];//客户端套接字数组
	char hSockname[WSA_MAXIMUM_WAIT_EVENTS][BUFSIZ];//客户端姓名数组
	WSAEVENT hEventArr[WSA_MAXIMUM_WAIT_EVENTS];//事件数组
	SOCKET hSockTarget[WSA_MAXIMUM_WAIT_EVENTS];//通信目标套接字数组
	WSAEVENT newEvent;
	WSANETWORKEVENTS netEvents;

	int numOfClntSock = 0;
	int strLen, i;
	int posInfo, startIdx;
	int clntAdrLen;
	char msg[BUF_SIZE];
	char temp[BUF_SIZE];
	int j;

	if (argc != 2) {
		printf("Usage: %s <port>\n", argv[0]);
		exit(1);
	}
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	for (i = 0; i < WSA_MAXIMUM_WAIT_EVENTS; i++)
	{
		memset(hSockname[i], 0, BUF_SIZE);
	}

	hServSock = socket(PF_INET, SOCK_STREAM, 0);
	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = htonl(INADDR_ANY);
	servAdr.sin_port = htons(atoi(argv[1]));

	if (bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
		ErrorHandling("bind() error");

	if (listen(hServSock, 5) == SOCKET_ERROR)
		ErrorHandling("listen() error");

	newEvent = WSACreateEvent();
	if (WSAEventSelect(hServSock, newEvent, FD_ACCEPT) == SOCKET_ERROR)
		ErrorHandling("WSAEventSelect() error");

	hSockArr[numOfClntSock] = hServSock;
	memcpy(hSockname[numOfClntSock], "server", 6);
	hEventArr[numOfClntSock] = newEvent;
	hSockTarget[numOfClntSock] = hServSock;
	numOfClntSock++;

	while (1)
	{
		posInfo = WSAWaitForMultipleEvents(
			numOfClntSock, hEventArr, FALSE, WSA_INFINITE, FALSE);
		startIdx = posInfo - WSA_WAIT_EVENT_0;

		for (i = startIdx; i < numOfClntSock; i++)
		{
			int sigEventIdx =
				WSAWaitForMultipleEvents(1, &hEventArr[i], TRUE, 0, FALSE);
			if ((sigEventIdx == WSA_WAIT_FAILED || sigEventIdx == WSA_WAIT_TIMEOUT))
			{
				continue;
			}
			else
			{
				sigEventIdx = i;
				WSAEnumNetworkEvents(
					hSockArr[sigEventIdx], hEventArr[sigEventIdx], &netEvents);
				if (netEvents.lNetworkEvents & FD_ACCEPT)
				{
					if (netEvents.iErrorCode[FD_ACCEPT_BIT] != 0)
					{
						puts("Accept Error");
						break;
					}
					clntAdrLen = sizeof(clntAdr);
					hClntSock = accept(
						hSockArr[sigEventIdx], (SOCKADDR*)&clntAdr, &clntAdrLen);
					memset(msg, 0, BUF_SIZE);
					recv(hClntSock, msg, BUF_SIZE, 0);
					newEvent = WSACreateEvent();
					WSAEventSelect(hClntSock, newEvent, FD_READ | FD_CLOSE);

					hEventArr[numOfClntSock] = newEvent;
					memcpy(hSockname[numOfClntSock], msg, strlen(msg));
					hSockArr[numOfClntSock] = hClntSock;
					hSockTarget[numOfClntSock] = 0;
					numOfClntSock++;
					printf("connected new client:%d\n", hClntSock);
				}

				if (netEvents.lNetworkEvents & FD_READ)
				{
					if (netEvents.iErrorCode[FD_READ_BIT] != 0)
					{
						puts("Read Error");
						break;
					}
					memset(msg, 0, BUF_SIZE);
					memset(temp, 0, BUF_SIZE);
					strLen = recv(hSockArr[sigEventIdx], msg, sizeof(msg), 0);
					if (strncmp(msg, "all", 3) == 0)//群发
					{
						memcpy(temp, msg + 3, strlen(msg) - 3);
						memcpy(msg, "[From group]:", 13);
						memcpy(msg + 13, temp, strlen(temp));
						for (j = 1; j < numOfClntSock; j++)
						{
							send(hSockArr[j], msg, strlen(msg), 0);
						}
					}
					else if (strcmp(msg, "cc") == 0)//发送已连接用户
					{
						for (j = 1; j < numOfClntSock; j++)
						{
							send(hSockArr[i], hSockname[j], strlen(hSockname[j]), 0);
							send(hSockArr[i], "#", 1, 0);
						}
						send(hSockArr[i], "\n", 1, 0);
					}
					else if (strncmp(msg, "aa", 2) == 0)//查找要连接的用户
					{
						memcpy(temp, msg + 2, strlen(msg) - 2);
						for (j = 1; j < numOfClntSock; j++)
						{
							if (strcmp(temp, hSockname[j]) == 0)
							{
								hSockTarget[i] = hSockArr[j];
								send(hSockArr[i], "The user is connected\n", 22, 0);
								break;
							}
						}
						if (j == numOfClntSock)
						{
							send(hSockArr[i], "The client is down!\n", 20, 0);
						}
					}
					else if (strncmp(msg, "dd", 2) == 0)
					{
						memcpy(temp, msg + 2, strlen(msg) - 2);
						send(hSockTarget[i], temp, strlen(temp), 0);
					}
					else
						send(hSockArr[i], "Communication failure!", 22, 0);

				}

				if (netEvents.lNetworkEvents & FD_CLOSE)
				{
					printf("Client %d closed!\n", hSockArr[sigEventIdx]);
					WSACloseEvent(hEventArr[sigEventIdx]);
					closesocket(hSockArr[sigEventIdx]);

					numOfClntSock--;
					Compress(hSockArr, hSockname, hEventArr, hSockTarget, sigEventIdx, numOfClntSock);
				}
			}
		}
	}
	WSACleanup();
	return 0;
}

void Compress(SOCKET hSockArr[], char hSockname[WSA_MAXIMUM_WAIT_EVENTS][BUFSIZ],WSAEVENT hEventArr[], SOCKET hSockTarget[],int idx, int total)
{
	int i;
	for (i = idx; i < total; i++)
	{
		hSockArr[i] = hSockArr[i + 1];
		memcpy(hSockname[i], hSockname[i + 1], BUF_SIZE);
		hEventArr[i] = hEventArr[i + 1];
		hSockTarget[i] = hSockTarget[i + 1];
	}
	memset(hSockname[i], 0, BUF_SIZE);
}
void ErrorHandling(char* msg)
{
	fputs(msg, stderr);
	fputc('\n', stderr);
	exit(1);
}
 //客户端:
 // ChatClient_win.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <process.h> 

#define BUF_SIZE 100
#define NAME_SIZE 20

unsigned WINAPI SendMsg(void* arg);
unsigned WINAPI RecvMsg(void* arg);
void ErrorHandling(char* msg);

char name[NAME_SIZE];
char buffer[BUF_SIZE];

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET hSock;
	SOCKADDR_IN servAdr;
	HANDLE hSndThread, hRcvThread;
	if (argc != 4) {
		printf("Usage : %s <IP> <port> <name>\n", argv[0]);
		exit(1);
	}
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	memcpy(name, argv[3], strlen(argv[3]));
	hSock = socket(PF_INET, SOCK_STREAM, 0);
	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = inet_addr(argv[1]);
	servAdr.sin_port = htons(atoi(argv[2]));
	if (connect(hSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
		ErrorHandling("connect() error");
	else
	{
		send(hSock, name, strlen(name),0);
		puts("Connected...........");
	}
	hSndThread =
		(HANDLE)_beginthreadex(NULL, 0, SendMsg, (void*)&hSock, 0, NULL);
	hRcvThread =
		(HANDLE)_beginthreadex(NULL, 0, RecvMsg, (void*)&hSock, 0, NULL);

	WaitForSingleObject(hSndThread, INFINITE);
	WaitForSingleObject(hRcvThread, INFINITE);
	closesocket(hSock);
	WSACleanup();
	return 0;
}

unsigned WINAPI SendMsg(void* arg)   // send thread main
{
	int sock = *((int*)arg);
	int len = strlen(name);
	char temp[BUF_SIZE];//临时变量

	int choice;//选择位

	while (1)//循环
	{
		puts("\n请输入你需要的服务:1[群聊]2[选择客户端发起聊天]3[查看已连接用户]4[退出]");
		scanf("%d", &choice);
		getchar();
		if (choice == 1)
		{
			while (1)
			{
				memset(buffer, 0, BUF_SIZE);
				printf("请输入需要发送的群聊消息:\n");
				memcpy(buffer, "all", 3);
				memcpy(buffer + 3, name, len);
				memcpy(buffer + len + 3, ":", 1);
				fgets(buffer + len + 4, BUF_SIZE - len - 4, stdin);
				if (!strcmp(buffer + len + 4, "q\n") || !strcmp(buffer + len + 4, "Q\n"))
				{
					break;
				}
				send(sock, buffer, strlen(buffer),0);
			}
		}
		else if (choice == 2)
		{
			memset(buffer, 0, BUF_SIZE);
			memset(temp, 0, BUF_SIZE);
			printf("请输入你需要通信的客户端姓名:");
			memcpy(buffer, "aa", 2);
			fgets(buffer + 2, BUF_SIZE - 2, stdin);
			send(sock, buffer, strlen(buffer) - 1,0);
			memcpy(temp, buffer + 2, strlen(buffer) - 3);
			while (1)
			{
				printf("请输入发给%s的消息:\n", temp);
				memset(buffer, 0, BUF_SIZE);
				memcpy(buffer, "dd", 2);
				memcpy(buffer + 2, name, len);
				memcpy(buffer + len + 2, ":", 1);
				fgets(buffer + len + 3, BUF_SIZE - len - 1, stdin);
				if (!strcmp(buffer + len + 3, "q\n") || !strcmp(buffer + len + 3, "Q\n"))
				{
					break;
				}
				send(sock, buffer, strlen(buffer),0);
			}
		}
		else if (choice == 3)
		{
			memset(buffer, 0, BUF_SIZE);
			memcpy(buffer, "cc", 2);
			send(sock, buffer, strlen(buffer),0);//发送aa标志信息,表示需要显示当前在线用户
			Sleep(1);
		}
		else
		{
			closesocket(sock);
			exit(0);
		}
	}
	return 0;
}

unsigned WINAPI RecvMsg(void* arg)   // read thread main
{
	int hSock = *((SOCKET*)arg);
	char nameMsg[NAME_SIZE + BUF_SIZE];
	int strLen;
	while (1)
	{
		strLen = recv(hSock, nameMsg, NAME_SIZE + BUF_SIZE - 1, 0);
		if (strLen == -1)
			return -1;
		nameMsg[strLen] = 0;
		fputs(nameMsg, stdout);
	}
	return 0;
}

void ErrorHandling(char* msg)
{
	fputs(msg, stderr);
	fputc('\n', stderr);
	exit(1);
}

测试结果:
在这里插入图片描述

(3) 使用重叠I/O模型实现回声服务器端(及客户端);

//服务端:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

#define BUF_SIZE 1024
void CALLBACK ReadCompRoutine(DWORD, DWORD, LPWSAOVERLAPPED, DWORD);
void CALLBACK WriteCompRoutine(DWORD, DWORD, LPWSAOVERLAPPED, DWORD);
void ErrorHandling(char* message);

typedef struct
{
	SOCKET hClntSock;
	char buf[BUF_SIZE];
	WSABUF wsaBuf;
} PER_IO_DATA, * LPPER_IO_DATA;

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET hLisnSock, hRecvSock;
	SOCKADDR_IN lisnAdr, recvAdr;
	LPWSAOVERLAPPED lpOvLp;
	DWORD recvBytes;
	LPPER_IO_DATA hbInfo;
	int mode = 1, recvAdrSz, flagInfo = 0;

	if (argc != 2) {
		printf("Usage: %s <port>\n", argv[0]);
		exit(1);
	}

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	hLisnSock = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
	ioctlsocket(hLisnSock, FIONBIO, &mode);   // for non-blocking socket

	memset(&lisnAdr, 0, sizeof(lisnAdr));
	lisnAdr.sin_family = AF_INET;
	lisnAdr.sin_addr.s_addr = htonl(INADDR_ANY);
	lisnAdr.sin_port = htons(atoi(argv[1]));

	if (bind(hLisnSock, (SOCKADDR*)&lisnAdr, sizeof(lisnAdr)) == SOCKET_ERROR)
		ErrorHandling("bind() error");
	if (listen(hLisnSock, 5) == SOCKET_ERROR)
		ErrorHandling("listen() error");

	recvAdrSz = sizeof(recvAdr);

	while (1)
	{
		SleepEx(100, TRUE);    // for alertable wait state
		hRecvSock = accept(hLisnSock, (SOCKADDR*)&recvAdr, &recvAdrSz);
		if (hRecvSock == INVALID_SOCKET)
		{
			if (WSAGetLastError() == WSAEWOULDBLOCK)
				continue;
			else
				ErrorHandling("accept() error");
		}
		puts("Client connected.....");

		lpOvLp = (LPWSAOVERLAPPED)malloc(sizeof(WSAOVERLAPPED));
		memset(lpOvLp, 0, sizeof(WSAOVERLAPPED));

		hbInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
		hbInfo->hClntSock = (DWORD)hRecvSock;
		(hbInfo->wsaBuf).buf = hbInfo->buf;
		(hbInfo->wsaBuf).len = BUF_SIZE;

		lpOvLp->hEvent = (HANDLE)hbInfo;
		WSARecv(hRecvSock, &(hbInfo->wsaBuf),
			1, &recvBytes, &flagInfo, lpOvLp, ReadCompRoutine);
	}
	closesocket(hRecvSock);
	closesocket(hLisnSock);
	WSACleanup();
	return 0;
}

void CALLBACK ReadCompRoutine(
	DWORD dwError, DWORD szRecvBytes, LPWSAOVERLAPPED lpOverlapped, DWORD flags)
{
	LPPER_IO_DATA hbInfo = (LPPER_IO_DATA)(lpOverlapped->hEvent);
	SOCKET hSock = hbInfo->hClntSock;
	LPWSABUF bufInfo = &(hbInfo->wsaBuf);
	DWORD sentBytes;

	if (szRecvBytes == 0)
	{
		closesocket(hSock);
		free(lpOverlapped->hEvent); free(lpOverlapped);
		puts("Client disconnected.....");
	}
	else    // echo!
	{
		bufInfo->len = szRecvBytes;
		WSASend(hSock, bufInfo, 1, &sentBytes, 0, lpOverlapped, WriteCompRoutine);
	}
}

void CALLBACK WriteCompRoutine(
	DWORD dwError, DWORD szSendBytes, LPWSAOVERLAPPED lpOverlapped, DWORD flags)
{
	LPPER_IO_DATA hbInfo = (LPPER_IO_DATA)(lpOverlapped->hEvent);
	SOCKET hSock = hbInfo->hClntSock;
	LPWSABUF bufInfo = &(hbInfo->wsaBuf);
	DWORD recvBytes;
	int flagInfo = 0;
	WSARecv(hSock, bufInfo,
		1, &recvBytes, &flagInfo, lpOverlapped, ReadCompRoutine);
}

void ErrorHandling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
 
//客户端:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

#define BUF_SIZE 1024
void ErrorHandling(char* message);

int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET hSocket;
	SOCKADDR_IN servAdr;
	char message[BUF_SIZE];
	int strLen, readLen;

	if (argc != 3) {
		printf("Usage: %s <IP> <port>\n", argv[0]);
		exit(1);
	}
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	hSocket = socket(PF_INET, SOCK_STREAM, 0);
	if (hSocket == INVALID_SOCKET)
		ErrorHandling("socket() error");

	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = inet_addr(argv[1]);
	servAdr.sin_port = htons(atoi(argv[2]));

	if (connect(hSocket, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR)
		ErrorHandling("connect() error!");
	else
		puts("Connected...........");

	while (1)
	{
		fputs("Input message(Q to quit): ", stdout);
		fgets(message, BUF_SIZE, stdin);
		if (!strcmp(message, "q\n") || !strcmp(message, "Q\n"))
			break;

		strLen = strlen(message);
		send(hSocket, message, strLen, 0);

		readLen = 0;
		while (1)
		{
			readLen += recv(hSocket, &message[readLen], BUF_SIZE - 1, 0);
			if (readLen >= strLen)
				break;
		}
		message[strLen] = 0;
		printf("Message from server: %s", message);
	}

	closesocket(hSocket);
	WSACleanup();
	return 0;
}

void ErrorHandling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}

测试结果:
在这里插入图片描述
在这里插入图片描述

(4) 使用重叠I/O模型编写聊天服务器端(及客户端);

//服务端:
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")  //加载 ws2_32.dll  


#define BUF_SIZE 1024
void CALLBACK ReadCompRoutine(DWORD, DWORD, LPWSAOVERLAPPED, DWORD);
void CALLBACK WriteCompRoutine(DWORD, DWORD, LPWSAOVERLAPPED, DWORD);
void ErrorHandling(char* message);

typedef struct
{
	SOCKET hClntSock;
	char buf[BUF_SIZE];
	WSABUF wsaBuf;
} PER_IO_DATA, * LPPER_IO_DATA;

SOCKET hClntSock[100];//所有客户端
char hSockname[100][20];//所有客户端姓名
SOCKET hSockTarget[100];
int CONNECNUM = 0;//计数
LPWSAOVERLAPPED overlap[100];//所有客户端的相关结构
// int overcount = 0;
char msg[BUF_SIZE];


int main(int argc, char* argv[])
{
	WSADATA wsaData;
	SOCKET hLisnSock, hRecvSock;
	SOCKADDR_IN lisnAdr, recvAdr;
	LPWSAOVERLAPPED lpOvLp;
	DWORD recvBytes = 0;
	LPPER_IO_DATA hbInfo;
	u_long mode = 1;
	DWORD  flagInfo = 0;
	int recvAdrSz = 0;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	hLisnSock = WSASocket(PF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
	ioctlsocket(hLisnSock, FIONBIO, &mode);   // for non-blocking socket(非阻塞套接字)

	memset(&lisnAdr, 0, sizeof(lisnAdr));
	lisnAdr.sin_family = AF_INET;
	lisnAdr.sin_addr.s_addr = htonl(INADDR_ANY);
	lisnAdr.sin_port = htons(atoi(argv[1]));

	if (bind(hLisnSock, (SOCKADDR*)&lisnAdr, sizeof(lisnAdr)) == SOCKET_ERROR)
		ErrorHandling("bind() error");
	if (listen(hLisnSock, 5) == SOCKET_ERROR)
		ErrorHandling("listen() error");

	recvAdrSz = sizeof(recvAdr);

	while (1)
	{
		SleepEx(100, TRUE);    // for alertable wait state(设置状态)
		hRecvSock = accept(hLisnSock, (SOCKADDR*)&recvAdr, &recvAdrSz);
		if (hRecvSock == INVALID_SOCKET)
		{
			if (WSAGetLastError() == WSAEWOULDBLOCK)//只表示无连接
				continue;
			else
				ErrorHandling("accept() error");
		}
		hClntSock[CONNECNUM] = hRecvSock;
		memset(msg, 0, BUF_SIZE);
		recv(hRecvSock, msg, BUF_SIZE, 0);
		memcpy(hSockname[CONNECNUM], msg, strlen(msg));
		printf("Client:%d connected.....\n",hRecvSock);

		lpOvLp = (LPWSAOVERLAPPED)malloc(sizeof(WSAOVERLAPPED));
		overlap[CONNECNUM++] = lpOvLp;//存入数组

		memset(lpOvLp, 0, sizeof(WSAOVERLAPPED));

		hbInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
		hbInfo->hClntSock = (DWORD)hRecvSock;

		memset(hbInfo->buf, 0, BUF_SIZE);
		(hbInfo->wsaBuf).buf = hbInfo->buf;
		(hbInfo->wsaBuf).len = BUF_SIZE;

		lpOvLp->hEvent = (HANDLE)hbInfo;//特殊类型转换
		//if (
		WSARecv(hRecvSock, &(hbInfo->wsaBuf),
			1, &recvBytes, &flagInfo, lpOvLp, ReadCompRoutine);
			if (WSAGetLastError() == WSA_IO_PENDING)
			{
				printf("接收数据中.\n");
			}
	}
	closesocket(hRecvSock);
	closesocket(hLisnSock);
	WSACleanup();
	return 0;
}

void CALLBACK ReadCompRoutine(//参数:(错误信息,实际收发字节数,WSA*的lpOverlapped参数,特性信息或0)
	DWORD dwError, DWORD szRecvBytes, LPWSAOVERLAPPED lpOverlapped, DWORD flags)
{
	int j,i;
	int l = 0;
	char temp[BUF_SIZE];
	LPPER_IO_DATA hbInfo = (LPPER_IO_DATA)(lpOverlapped->hEvent);//类型转回
	SOCKET hSock = hbInfo->hClntSock;
	LPWSABUF bufInfo = &(hbInfo->wsaBuf);
	DWORD sentBytes;
	for (j = 0; j < CONNECNUM; j++)
	{
		if (hClntSock[j] == hSock)
		{
			break;
		}
	}
	if (szRecvBytes == 0)
	{
		for (i = j; i < CONNECNUM; i++)
		{
			hClntSock[i] = hClntSock[i + 1];
			memcpy(hSockname[i], hSockname[i + 1], 20);
			overlap[i] = overlap[i + 1];
			hSockTarget[i] = hSockTarget[i + 1];
		}
		closesocket(hSock);
		printf("Client:%d disconnected.....\n",hSock);
		memset(hSockname[i], 0, 20);
		CONNECNUM--;
	}
	else
	{
		bufInfo->len = szRecvBytes;
		memset(msg, 0, BUF_SIZE);
		memset(temp, 0, BUF_SIZE);
		if (strncmp(bufInfo->buf, "all", 3) == 0)//群发
		{
			memcpy(temp, bufInfo->buf + 3, szRecvBytes - 3);
			memset(bufInfo->buf, 0, BUF_SIZE);
			memcpy(bufInfo->buf, "[From group]:", 13);
			memcpy(bufInfo->buf + 13, temp, strlen(temp));
			bufInfo->len = szRecvBytes+10;
			for (i = 0; i < CONNECNUM; i++)
			{
				WSASend(hClntSock[i], bufInfo, 1, &sentBytes, 0, lpOverlapped, WriteCompRoutine);
			}
		}
		else if (strncmp(bufInfo->buf, "cc", 2) == 0)//发送已连接用户
		{
			for (i = 0; i < CONNECNUM; i++)
			{
				memcpy(msg + l, hSockname[i], strlen(hSockname[i]));
				l += strlen(hSockname[i]);
				memcpy(msg + l, "#", 1);
				l += 1;
			}
			memcpy(msg + l, "\n", 1);
			memset(bufInfo->buf, 0, BUF_SIZE);
			memcpy(bufInfo->buf, msg, strlen(msg));
			bufInfo->len = strlen(msg);
			WSASend(hSock, bufInfo, 1, &sentBytes, 0, lpOverlapped, WriteCompRoutine);
		}
		else if (strncmp(bufInfo->buf, "aa", 2) == 0)//查找要连接的用户
		{
			memcpy(temp, bufInfo->buf + 2, szRecvBytes - 2);
			for (i = 0; i < CONNECNUM; i++)
			{
				if (strcmp(temp, hSockname[i]) == 0)
				{
					hSockTarget[j] = hClntSock[i];
					memset(bufInfo->buf, 0, BUF_SIZE);
					memcpy(bufInfo->buf, "The user is connected\n", 22);
					bufInfo->len = 22;
					WSASend(hSock, bufInfo, 1, &sentBytes, 0, overlap[j], WriteCompRoutine);
					break;
				}
			}
			if (i == CONNECNUM)
			{
				memset(bufInfo->buf, 0, BUF_SIZE);
				memcpy(bufInfo->buf, "The client is down!\n", 20);
				bufInfo->len = 20;
				WSASend(hSock, bufInfo, 1, &sentBytes, 0, overlap[j], WriteCompRoutine);
			}
		}
		else if (strncmp(bufInfo->buf, "dd", 2) == 0)
		{
			memcpy(temp, bufInfo->buf + 2, szRecvBytes - 2);
			memset(bufInfo->buf, 0, BUF_SIZE);
			memcpy(bufInfo->buf, temp, strlen(temp));
			bufInfo->len = strlen(temp);
			WSASend(hSockTarget[j], bufInfo, 1, &sentBytes, 0, overlap[j], WriteCompRoutine);
			// send(hSockTarget[i], temp, strlen(temp), 0);
		}
		else
		{
			memcpy(bufInfo->buf, "Communication failure!\n", 23);
			bufInfo->len = 20;
			WSASend(hSock, bufInfo, 1, &sentBytes, 0, overlap[j], WriteCompRoutine);
		}
	}
}

void CALLBACK WriteCompRoutine(//参数:(错误信息,实际收发字节数,WSA*的lpOverlapped参数,特性信息或0)
	DWORD dwError, DWORD szSendBytes, LPWSAOVERLAPPED lpOverlapped, DWORD flags)
{
	LPPER_IO_DATA hbInfo = (LPPER_IO_DATA)(lpOverlapped->hEvent);
	SOCKET hSock = hbInfo->hClntSock;
	LPWSABUF bufInfo = &(hbInfo->wsaBuf);
	DWORD recvBytes = 0;
	DWORD flagInfo = 0;
	int result = WSARecv(hSock, bufInfo,
		1, &recvBytes, &flagInfo, lpOverlapped, ReadCompRoutine);
}

void ErrorHandling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
//客户端:
//同(2)的客户端

测试结果:
在这里插入图片描述

(5) 使用完成端口模型实现回声服务器端(及客户端);

//服务端:
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <winsock2.h>
#include <windows.h>

#define BUF_SIZE 100
#define READ	3
#define	WRITE	5

typedef struct    // socket info
{
	SOCKET hClntSock;
	SOCKADDR_IN clntAdr;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;

typedef struct    // buffer info
{
	OVERLAPPED overlapped;
	WSABUF wsaBuf;
	char buffer[BUF_SIZE];
	int rwMode;    // READ or WRITE
} PER_IO_DATA, * LPPER_IO_DATA;

DWORD WINAPI EchoThreadMain(LPVOID CompletionPortIO);
void ErrorHandling(char* message);

int main(int argc, char* argv[])
{
	WSADATA	wsaData;
	HANDLE hComPort;
	SYSTEM_INFO sysInfo;
	LPPER_IO_DATA ioInfo;
	LPPER_HANDLE_DATA handleInfo;

	SOCKET hServSock;
	SOCKADDR_IN servAdr;
	int recvBytes, i, flags = 0;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
	GetSystemInfo(&sysInfo);

	for (i = 0; i < sysInfo.dwNumberOfProcessors; i++)
		_beginthreadex(NULL, 0, EchoThreadMain, (LPVOID)hComPort, 0, NULL);

	hServSock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = htonl(INADDR_ANY);
	servAdr.sin_port = htons(atoi(argv[1]));

	bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr));
	listen(hServSock, 5);

	while (1)
	{
		SOCKET hClntSock;
		SOCKADDR_IN clntAdr;
		int addrLen = sizeof(clntAdr);

		hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &addrLen);

		handleInfo = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
		handleInfo->hClntSock = hClntSock;
		memcpy(&(handleInfo->clntAdr), &clntAdr, addrLen);

		CreateIoCompletionPort((HANDLE)hClntSock, hComPort, (DWORD)handleInfo, 0);

		ioInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
		memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
		ioInfo->wsaBuf.len = BUF_SIZE;
		ioInfo->wsaBuf.buf = ioInfo->buffer;
		ioInfo->rwMode = READ;

		WSARecv(handleInfo->hClntSock, &(ioInfo->wsaBuf),
			1, &recvBytes, &flags, &(ioInfo->overlapped), NULL);
	}
	return 0;
}

DWORD WINAPI EchoThreadMain(LPVOID pComPort)
{
	HANDLE hComPort = (HANDLE)pComPort;
	SOCKET sock;
	DWORD bytesTrans;
	LPPER_HANDLE_DATA handleInfo;
	LPPER_IO_DATA ioInfo;
	DWORD flags = 0;

	while (1)
	{
		GetQueuedCompletionStatus(hComPort, &bytesTrans,
			(LPDWORD)&handleInfo, (LPOVERLAPPED*)&ioInfo, INFINITE);
		sock = handleInfo->hClntSock;

		if (ioInfo->rwMode == READ)
		{
			puts("message received!");
			if (bytesTrans == 0)    // EOF 
			{
				closesocket(sock);
				free(handleInfo); free(ioInfo);
				continue;
			}

			memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
			ioInfo->wsaBuf.len = bytesTrans;
			ioInfo->rwMode = WRITE;
			WSASend(sock, &(ioInfo->wsaBuf),
				1, NULL, 0, &(ioInfo->overlapped), NULL);

			ioInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
			memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
			ioInfo->wsaBuf.len = BUF_SIZE;
			ioInfo->wsaBuf.buf = ioInfo->buffer;
			ioInfo->rwMode = READ;
			WSARecv(sock, &(ioInfo->wsaBuf),
				1, NULL, &flags, &(ioInfo->overlapped), NULL);
		}
		else
		{
			puts("message sent!");
			free(ioInfo);
		}
	}
	return 0;
}

void ErrorHandling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
//客户端:
//同(3)客户端

测试结果:
在这里插入图片描述
在这里插入图片描述

(6) 使用完成端口模型编写聊天服务器端(及客户端)。

//服务端:
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include <winsock2.h>
#include <windows.h>

#define BUF_SIZE 100
#define READ	3
#define	WRITE	5

typedef struct    // socket info
{
	SOCKET hClntSock;
	SOCKADDR_IN clntAdr;
	SOCKET hTargetSock;
	char hClntname[20];
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;

typedef struct    // buffer info
{
	OVERLAPPED overlapped;
	WSABUF wsaBuf;
	char buffer[BUF_SIZE];
	int rwMode;    // READ or WRITE
} PER_IO_DATA, * LPPER_IO_DATA;

DWORD WINAPI ChatThreadMain(LPVOID CompletionPortIO);
void ErrorHandling(char* message);

SOCKET hClntSocks[100];//所有客户端
char hSockname[100][20];//所有客户端姓名
SOCKET hSockTarget[100];
int CONNECNUM = 0;//计数
char msg[BUF_SIZE];

int main(int argc, char* argv[])
{
	WSADATA	wsaData;
	HANDLE hComPort;
	SYSTEM_INFO sysInfo;
	LPPER_IO_DATA ioInfo;
	LPPER_HANDLE_DATA handleInfo;

	SOCKET hServSock;
	SOCKADDR_IN servAdr;
	int recvBytes, i, flags = 0;

	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
		ErrorHandling("WSAStartup() error!");

	hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
	GetSystemInfo(&sysInfo);

	for (i = 0; i < sysInfo.dwNumberOfProcessors; i++)
		_beginthreadex(NULL, 0, ChatThreadMain, (LPVOID)hComPort, 0, NULL);

	hServSock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
	memset(&servAdr, 0, sizeof(servAdr));
	servAdr.sin_family = AF_INET;
	servAdr.sin_addr.s_addr = htonl(INADDR_ANY);
	servAdr.sin_port = htons(atoi(argv[1]));

	bind(hServSock, (SOCKADDR*)&servAdr, sizeof(servAdr));
	listen(hServSock, 5);

	while (1)
	{
		SOCKET hClntSock;
		SOCKADDR_IN clntAdr;
		int addrLen = sizeof(clntAdr);

		hClntSock = accept(hServSock, (SOCKADDR*)&clntAdr, &addrLen);
		hClntSocks[CONNECNUM] = hClntSock;
		printf("Client:%d connected.....\n", hClntSock);
		memset(msg, 0, BUF_SIZE);
		recv(hClntSock, msg, BUF_SIZE, 0);
		memcpy(hSockname[CONNECNUM], msg, strlen(msg));
		CONNECNUM++;
		handleInfo = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));
		handleInfo->hClntSock = hClntSock;
		memcpy(&(handleInfo->clntAdr), &clntAdr, addrLen);

		CreateIoCompletionPort((HANDLE)hClntSock, hComPort, (DWORD)handleInfo, 0);

		ioInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
		memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
		ioInfo->wsaBuf.len = BUF_SIZE;
		memset(ioInfo->buffer, 0, BUF_SIZE);
		ioInfo->wsaBuf.buf = ioInfo->buffer;
		ioInfo->rwMode = READ;

		WSARecv(handleInfo->hClntSock, &(ioInfo->wsaBuf),
			1, &recvBytes, &flags, &(ioInfo->overlapped), NULL);
	}
	return 0;
}

DWORD WINAPI ChatThreadMain(LPVOID pComPort)
{
	int i;
	int l=0;
	HANDLE hComPort = (HANDLE)pComPort;
	SOCKET sock;
	DWORD bytesTrans;
	LPPER_HANDLE_DATA handleInfo;
	LPPER_IO_DATA ioInfo;
	DWORD flags = 0;
	char temp[BUF_SIZE];

	while (1)
	{
		GetQueuedCompletionStatus(hComPort, &bytesTrans,
			(LPDWORD)&handleInfo, (LPOVERLAPPED*)&ioInfo, INFINITE);
		sock = handleInfo->hClntSock;
		for (i = 0; i < CONNECNUM; i++)
		{
			if (hClntSocks[i] == sock)
				break;
		}
		if (ioInfo->rwMode == READ)
		{
			puts("message received!");
			if (bytesTrans == 0)    // EOF 
			{
				for (int j = i; j < CONNECNUM; j++)
				{
					hClntSocks[j] = hClntSocks[j + 1];
					memcpy(hSockname[j], hSockname[j + 1], 20);
					hSockTarget[j] = hSockTarget[j + 1];
				}
				printf("Client:%d disconnected.....\n", sock);
				memset(hSockname[i], 0, 20);
				CONNECNUM--;
				closesocket(sock);
				free(handleInfo); free(ioInfo);
				continue;
			}
			else
			{
				memset(msg, 0, BUF_SIZE);
				memset(temp, 0, BUF_SIZE);
				if (strncmp(ioInfo->wsaBuf.buf, "all", 3) == 0)//群发
				{
					memcpy(temp, ioInfo->wsaBuf.buf+3, bytesTrans - 3);
					memset(ioInfo->wsaBuf.buf, 0, BUF_SIZE);
					memcpy(ioInfo->wsaBuf.buf, "[From group]:", 13);
					memcpy(ioInfo->wsaBuf.buf + 13, temp, strlen(temp));
					memcpy(ioInfo->wsaBuf.buf + bytesTrans + 10, "\n", 1);
					ioInfo->wsaBuf.len = bytesTrans + 11;
					ioInfo->rwMode = WRITE;
					for (int j = 0; j < CONNECNUM; j++)
					{
						//WSASend(hClntSocks[j], &(ioInfo->wsaBuf), 1, NULL, 0, &(ioInfo->overlapped), NULL);
						send(hClntSocks[j], ioInfo->wsaBuf.buf, ioInfo->wsaBuf.len, 1);
					}
				}
				else if (strncmp(ioInfo->wsaBuf.buf, "cc", 2) == 0)//发送已连接用户
				{
					for (int j = 0; j < CONNECNUM; j++)
					{
						memcpy(msg + l, hSockname[j], strlen(hSockname[j]));
						l += strlen(hSockname[j]);
						memcpy(msg + l, "#", 1);
						l += 1;
					}
					memcpy(msg + l, "\n", 1);
					memset(ioInfo->wsaBuf.buf, 0, BUF_SIZE);
					memcpy(ioInfo->wsaBuf.buf, msg, strlen(msg));
					ioInfo->wsaBuf.len = strlen(msg);
					WSASend(sock, &(ioInfo->wsaBuf), 1, NULL, 0, &(ioInfo->overlapped), NULL);
				}
				else if (strncmp(ioInfo->wsaBuf.buf, "aa", 2) == 0)//查找要连接的用户
				{
					memcpy(temp, ioInfo->wsaBuf.buf + 2, bytesTrans - 2);
					for (int j = 0; j < CONNECNUM; j++)
					{
						if (strcmp(temp, hSockname[j]) == 0)
						{
							hSockTarget[i] = hClntSocks[j];
							memset(ioInfo->wsaBuf.buf, 0, BUF_SIZE);
							memcpy(ioInfo->wsaBuf.buf, "The user is connected\n", 22);
							ioInfo->wsaBuf.len = 22;
							WSASend(sock, &(ioInfo->wsaBuf), 1, NULL, 0, &(ioInfo->overlapped), NULL);
							break;
						}
					}
					if (i == CONNECNUM)
					{
						memset(ioInfo->wsaBuf.buf, 0, BUF_SIZE);
						memcpy(ioInfo->wsaBuf.buf, "The client is down!\n", 20);
						ioInfo->wsaBuf.len = 20;
						WSASend(sock, &(ioInfo->wsaBuf), 1, NULL, 0, &(ioInfo->overlapped), NULL);
					}
				}
				else if (strncmp(ioInfo->wsaBuf.buf, "dd", 2) == 0)
				{
					memcpy(temp, ioInfo->wsaBuf.buf + 2, bytesTrans - 2);
					memset(ioInfo->wsaBuf.buf, 0, BUF_SIZE);
					memcpy(ioInfo->wsaBuf.buf, temp, strlen(temp));
					ioInfo->wsaBuf.len = strlen(temp);
					WSASend(hSockTarget[i], &(ioInfo->wsaBuf), 1, NULL, 0, &(ioInfo->overlapped), NULL);
				}
				else
				{
					memcpy(ioInfo->wsaBuf.buf, "Communication failure!\n", 23);
					ioInfo->wsaBuf.len = 20;
					break;
					WSASend(sock, &(ioInfo->wsaBuf), 1, NULL, 0, &(ioInfo->overlapped), NULL);
				}
			}
			ioInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
			memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
			ioInfo->wsaBuf.len = BUF_SIZE;
			memset(ioInfo->buffer, 0, BUF_SIZE);
			ioInfo->wsaBuf.buf = ioInfo->buffer;
			ioInfo->rwMode = READ;
			WSARecv(sock, &(ioInfo->wsaBuf),
				1, NULL, &flags, &(ioInfo->overlapped), NULL);
		}
		else
		{
			puts("message sent!");
			free(ioInfo);
		}
	}
	return 0;
}

void ErrorHandling(char* message)
{
	fputs(message, stderr);
	fputc('\n', stderr);
	exit(1);
}
//客户端同(2)客户端

测试结果:
在这里插入图片描述

在IOCP服务器的编写中,发送群聊消息后服务器自动关闭,经过反复调试找不到问题所在,可能与系统线程相冲突有关。从而对程序进行了改正,暂时使用send对每一个套接字发送消息。
三种模型的聊天服务器均实现了一对一聊天、群聊等功能。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值