NoteDeep

代码逻辑:

网络头文件、网络库:

打开网络库:

校验版本:

创建socket:

绑定地址端口:

完成端口和socketServer绑定:

HANDLE WINAPI CreateIoCompletionPort(
_In_ HANDLE FileHandle,
_In_opt_ HANDLE ExistingCompletionPort,
_In_ ULONG_PTR CompletionKey,
_In_ DWORD NumberOfConcurrentThreads
);
功能:创建完成端口, 将完成端口和socket绑定
参数
创建完成端口:
1.参数1:INVALID_HANDLE_VALUE,
2.此时参数2必须填NULL,
3.参数3忽略, 填0,
4.参数4允许此端口上最多同时运行的线程数量, 0:系统自动获取CPU核数2倍
绑定socket和完成端口:
1.服务器socket
2.完成端口变量
3.和socket一起绑定的信息(可以是下标等, 调用GetQueuedCompletionStatus()后会获得该信息, 用来标识到底是哪个socket)
4.忽略:0


返回值
创建完成端口:
成功:返回完成端口变量
失败:0, WSAGetLastError():完成端口是windows一种机制, 和网络无关, 文件操作也可以用到
绑定:
成功:返回完成端口变量
失败:与绑定的完成端口不同

开始监听:

投递AcceptEx:

在投递之后创建线程:

获取操作系统的相关信息:内核数量
void GetSystemInfo(
LPSYSTEM_INFO lpSystemInfo
);
创建线程
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
__drv_aliasesMem LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
);

参数
1.线程句柄是否能继承:NULL不继承
指定线程执行权限:NULL默认
2.指定线程栈的大小:0默认1M, 以字节为单位(保留/提交由参数5决定)
3.线程函数的地址
DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);
4.外部给线程传递数据
5.线程状态:
立即执行:0
CREATE_SUSPENDED:挂起(随时可以激活)
STACK_SIZE_PARAM_IS_A_PESERVATION:和参数2关联, 设置:参数2就是栈保留大小, 不设置:参数2就是栈提交大小
6.线程ID:可以填NULL

返回值
成功:线程句柄(内核对象)释放线程:CloseHandle
失败:NULL, GetLastError()

栈提交大小:
物理内存上的空间

栈保留大小:
虚拟内存上的空间

修改主线程栈区大小:
链接器--系统--堆栈保留大小

线程内部:

DWORD WINAPI ThreadProc(
_In_ LPVOID lpParameter
);

BOOL WINAPI GetQueuedCompletionStatus(
_In_ HANDLE CompletionPort,
_Out_ LPDWORD lpNumberOfBytes,
_Out_ PULONG_PTR lpCompletionKey,
_Out_ LPOVERLAPPED *lpOverlapped,
_In_ DWORD dwMilliseconds
);
功能:尝试从指定的IO完成端口取出IO完成数据包, 没有通知时, 线程挂起, 不占用CPU时间片
参数
1.完成端口
2.接收或发送的字节数
3.CreateIoCompletionPort传递过来的数据
4.反馈给我们的重叠结构
5.等待时间
如果通知队列里什么都没有, 是否等待
INFINITE:一直等待

返回值
成功:TRUE
失败:FALSE, GetLastError

分类处理
1.AcceptEx:
给socket绑定上完成端口
投递recv
投递send
投递accept
2.WSARecv:
接收/发送的字节数 = 0:客户端退出
打印数据
继续投递WSARecv
3.WSASend:
... ...

完成端口所有处理都放在线程中即可, 所有的操作完成之后都会给完成端口发送通知, 所以PostAccept、PostRecv、PostSend函数中不用写处理代码

退出:

bFlag作为线程的循环变量












评论列表

    代码逻辑: