windows TCP/IP 网络编程(七)5种windows网络模型(5)完成端口

在这里插入图片描述
本文思维导图

1 完成端口模型介绍

在这里插入图片描述

2 代码逻辑

在这里插入图片描述
在这里插入图片描述

2.1 创建完成端口

在这里插入图片描述

2.2 完成端口与socketServer绑定

HANDLE hRes = CreateIoCompletionPort((HANDLE)sockListen, hPort, sockListen, 0);

2.3 创建线程在这里插入图片描述

2.4 完成端口

2.4.1 投递异步接收链接请求

在这里插入图片描述

2.4.2 WSARecv 投递异步接收信息

int WSAAPI WSARecv(
  [in]      SOCKET                             s,
  [in, out] LPWSABUF                           lpBuffers,
  [in]      DWORD                              dwBufferCount,
  [out]     LPDWORD                            lpNumberOfBytesRecvd,
  [in, out] LPDWORD                            lpFlags,
  [in]      LPWSAOVERLAPPED                    lpOverlapped,
  [in]      LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
);

在这里插入图片描述
在这里插入图片描述

2.4.3 WSASend 投递异步发送消息

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

#include <Winsock2.h>
#include <mswsock.h>

#include <string.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Mswsock.lib")

#define MAX_COUNT  1024
#define MAX_RECV_COUNT  1024

SOCKET all_socks[MAX_COUNT];
OVERLAPPED all_olp[MAX_COUNT];
int count;
HANDLE hPort;
HANDLE *pThread;
int process_count;

//接收缓冲区
char recv_buf[MAX_RECV_COUNT];

int PostAccept(void);
int PostRecv(int index);
int PostSend(int index);

void Clear(void)
{
	for (int i = 0; i < count; i++)
	{
		if (0 == all_socks[i])
			continue;
		closesocket(all_socks[i]);
		WSACloseEvent(all_olp[i].hEvent);
	}
}

BOOL g_flag = TRUE;

BOOL WINAPI fun(DWORD dwCtrlType)
{
	switch (dwCtrlType)
	{
	case CTRL_CLOSE_EVENT:
		//释放所有socket
		CloseHandle(hPort);
		Clear();

		g_flag = FALSE;

		//释放线程句柄
		for (int i = 0; i < process_count; i++)
		{
			//TerminateThread(pThread[i],);
			CloseHandle(pThread[i]);			
		}
		free(pThread);

		break;
	}
	return TRUE;
}
DWORD WINAPI ThreadProc(LPVOID lpParameter);

int main(void)
{
	SetConsoleCtrlHandler(fun, TRUE);
	WORD wdVersion = MAKEWORD(2, 2); 
	WSADATA wdScokMsg;
	int nRes = WSAStartup(wdVersion, &wdScokMsg);

	if (0 != nRes)
	{
		switch (nRes)
		{
		case WSASYSNOTREADY:
			printf("重启下电脑试试,或者检查网络库");
			break;
		case WSAVERNOTSUPPORTED:
			printf("请更新网络库");
			break;
		case WSAEINPROGRESS:
			printf("请重新启动");
			break;
		case WSAEPROCLIM:
			printf("请尝试关掉不必要的软件,以为当前网络运行提供充足资源");
			break;
		}
		return  0;
	}

	//校验版本
	if (2 != HIBYTE(wdScokMsg.wVersion) || 2 != LOBYTE(wdScokMsg.wVersion))
	{
		//说明版本不对
		//清理网络库
		WSACleanup();
		return 0;
	}

	SOCKET socketServer = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	//int a = WSAGetLastError();
	if (INVALID_SOCKET == socketServer)
	{
		int a = WSAGetLastError();
		//清理网络库
		WSACleanup();
		return 0;
	}

	struct sockaddr_in si;
	si.sin_family = AF_INET;
	si.sin_port = htons(12345);
	si.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	//int a = ~0;
	if (SOCKET_ERROR == bind(socketServer, (const struct sockaddr *)&si, sizeof(si)))
	{
		//出错了
		int a = WSAGetLastError();
		//释放
		closesocket(socketServer);
		//清理网络库
		WSACleanup();
		return 0;
	}

	all_socks[count] = socketServer;
	all_olp[count].hEvent = WSACreateEvent();
	count++;

	//创建完成端口
	hPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
	if (0 == hPort)
	{
		int a = GetLastError();
		printf("%d\n", a);
		closesocket(socketServer);
		//清理网络库
		WSACleanup();
		return 0;
	}
	//绑定
	HANDLE hPort1 = CreateIoCompletionPort((HANDLE)socketServer, hPort, 0, 0);
	if (hPort1 != hPort)
	{
		int a = GetLastError();
		printf("%d\n", a);

		CloseHandle(hPort);
		closesocket(socketServer);
		//清理网络库
		WSACleanup();
		return 0;
	}

	if (SOCKET_ERROR == listen(socketServer, SOMAXCONN))
	{
		//出错了
		int a = WSAGetLastError();
		//释放
		CloseHandle(hPort);
		closesocket(socketServer);
		//清理网络库
		WSACleanup();
		return 0;
	}

	if (0 != PostAccept())
	{
		Clear();
		//清理网络库
		WSACleanup();
		return 0;
	}
	//创建线程数量有了
	SYSTEM_INFO system_processors_count;
	GetSystemInfo(&system_processors_count);
	process_count = system_processors_count.dwNumberOfProcessors;

	//创建
	pThread = (HANDLE*)malloc(sizeof(HANDLE)*process_count);

	for (int i = 0; i < process_count; i++)
	{
		pThread[i] = CreateThread(NULL, 0, ThreadProc, hPort, 0, NULL);
		if (NULL == pThread[i])
		{
			int a = GetLastError();
			printf("%d\n", a);
			CloseHandle(hPort);
			closesocket(socketServer);
			//清理网络库
			WSACleanup();
			return 0;
		}
	}

	//阻塞
	while (1)
	{
		Sleep(1000);
	}

	//释放线程句柄
	for (int i = 0; i < process_count; i++)
	{
		CloseHandle(pThread[i]);
	}
	free(pThread);


	CloseHandle(hPort);
	Clear();
	//清理网络库
	WSACleanup();
	
	system("pause");
	return 0;
}

DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
	HANDLE port = (HANDLE)lpParameter;
	DWORD      number_of_bytes;
	ULONG_PTR index;
	LPOVERLAPPED lpOverlapped;
	while (g_flag)
	{
		BOOL bFlag = GetQueuedCompletionStatus(port, &number_of_bytes, &index, &lpOverlapped, INFINITE);
		if (FALSE == bFlag)
		{
			int a = GetLastError();
			if (64 == a)
			{
				printf("force close\n");
			}
			printf("%d\n", a);
			continue;
		}
		//处理
		//accept
		if (0 == index)
		{
			printf("accept\n");
			//绑定到完成端口
			HANDLE hPort1 = CreateIoCompletionPort((HANDLE)all_socks[count], hPort, count, 0);
			if (hPort1 != hPort)
			{
				int a = GetLastError();
				printf("%d\n", a);
				closesocket(all_socks[count]);
				continue;
			}
			PostSend(count);
			//新客户端投递recv
			PostRecv(count);
			count++;
			PostAccept();
		}
		else
		{
			if (0 == number_of_bytes)
			{
				//客户端下线
				printf("close\n");
				//关闭
				closesocket(all_socks[index]);
				WSACloseEvent(all_olp[index].hEvent);
				//从数组中删掉
				all_socks[index] = 0;
				all_olp[index].hEvent = NULL;
			}
			else
			{
				if (0 != recv_buf[0])
				{
					//收到  recv
					printf("%s\n", recv_buf);
					memset(recv_buf, 0, sizeof(recv_buf));
					//
					PostRecv(index);
				}
				else
				{
					//send
					printf("send ok\n");
				}
			}
		}
	}
	
	return 0;
}

int PostAccept()
{
	all_socks[count] = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
	all_olp[count].hEvent = WSACreateEvent();

	char str[1024] = { 0 };
	DWORD dwRecvcount;

	BOOL bRes = AcceptEx(all_socks[0], all_socks[count], str, 0, sizeof(struct sockaddr_in) + 16,
		sizeof(struct sockaddr_in) + 16, &dwRecvcount, &all_olp[0]);

	int a = WSAGetLastError();
	if (ERROR_IO_PENDING != a)
	{
		//函数执行出错
		return 1;
	}
	return 0;
}

int PostRecv(int index)
{
	WSABUF wsabuf;
	wsabuf.buf = recv_buf;
	wsabuf.len = MAX_RECV_COUNT;

	DWORD dwRecvCount;
	DWORD dwFlag = 0;
	int nRes = WSARecv(all_socks[index], &wsabuf, 1, &dwRecvCount, &dwFlag, &all_olp[index], NULL);

	int a = WSAGetLastError();
	if (ERROR_IO_PENDING != a)
	{
		//函数执行出错
		return 1;
	}
	return 0;
}

int PostSend(int index)
{
	WSABUF wsabuf;
	wsabuf.buf = "你好";
	wsabuf.len = MAX_RECV_COUNT;

	DWORD dwSendCount;
	DWORD dwFlag = 0;
	int nRes = WSASend(all_socks[index], &wsabuf, 1, &dwSendCount, dwFlag, &all_olp[index], NULL);

	int a = WSAGetLastError();
	if (ERROR_IO_PENDING != a)
	{
		//延迟处理
		//函数执行出错
		return 1;
	}
	return 0;
}


DEMO

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值