#include<iostream>
#include<WinSock2.h>
#include<Windows.h>
#include<process.h>
#pragma comment(lib,"ws2_32.lib")
#define BUF_SIZE 100
#define READ 3
#define WRITE 5
using namespace std;
typedef struct { //客户端信息
SOCKET hclientSocket;
SOCKADDR_IN clientAddr;
}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;
int k, l, m, n;
typedef struct {
OVERLAPPED overlapped; //I/O缓冲和重叠I/O都会使用 事件对象有两种状态 signaled:完成IO unsignaled: 未完成
WSABUF wsaBuf;
char buffer[BUF_SIZE]; //数据缓冲区
int rwMode; // 操作类型:读或写
}PER_IO_DATA,*LPPER_IO_DATA;
unsigned WINAPI EchoThreadMain(LPVOID CompletionPortIO);
void main() {
WSADATA wsadata;
HANDLE hComPort;
SYSTEM_INFO sysInfo;
LPPER_IO_DATA ioInfo;
LPPER_HANDLE_DATA handleInfo;
SOCKET serverSocket;
SOCKADDR_IN serverAddr;
unsigned int i;
DWORD recvBytes,flags = 0;
if(WSAStartup(MAKEWORD(2, 2), &wsadata)!=0)
cout<<"WSAStartup() error"<<endl;
//创建cp对象(第二个参数为0,所以是新建的一个iocp),最后一个参数为0 创建和CPU核数相同的线程 返回NULL即为创建失败
hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
GetSystemInfo(&sysInfo); //获取系统信息
for (i = 0; i < sysInfo.dwNumberOfProcessors; i++) //根据核数创建线程并传递给cp对象句柄
{ // 创建安全线程
_beginthreadex(NULL, 0 ,EchoThreadMain, (LPVOID)hComPort, 0, NULL);
}
//最后一个参数是:创建重叠IO非阻塞模式的TCP套接字
serverSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
if (serverSocket == INVALID_SOCKET)
cout << "socket() error" << endl;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port = htons(8000);
if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
cout << "bind () error" << endl;
listen(serverSocket, 5);
cout << "服务器启动成功!" << endl;
while (1) {
SOCKET clientSocket;
SOCKADDR_IN clientAddr;
int addrLen = sizeof(clientAddr);
clientSocket = accept(serverSocket, (SOCKADDR*)&clientAddr, &addrLen);
if (clientSocket != INVALID_SOCKET) cout << "已有客户端连接:" << clientSocket << endl;
handleInfo = (LPPER_HANDLE_DATA)malloc(sizeof(PER_HANDLE_DATA));//开辟地址创建客户信息句柄
handleInfo->hclientSocket = clientSocket; //将accep函数的客户端套接字赋给句柄
memcpy(&(handleInfo->clientAddr), &clientAddr, addrLen); //拷贝地址赋给句柄
//将accept传来的客户套接字和客户端地址和已存在的cp对象绑定,最后一个参数为0表示允许和CPU核数相同的线程访问该函数
CreateIoCompletionPort((HANDLE)clientSocket, 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->hclientSocket, &(ioInfo->wsaBuf),1, &recvBytes, &flags, &(ioInfo->overlapped), NULL);
//参数:1重叠IO套接字 2保存接受信息的结构体数组 3第二个参数数组的长度 4保存接受消息大小的变量地址 5设置或读取传输特性的消息
// 6事件对象的状态 7Routine函数地址
}
}
unsigned WINAPI EchoThreadMain(LPVOID pComPort)
{
cout << "线程 NO. " << GetCurrentThreadId() << endl;
cout << "EchoThreadMain() 初始化" << endl;
HANDLE hComPort = (HANDLE)pComPort;
SOCKET sock;
DWORD bytesTrans;
LPPER_HANDLE_DATA handleInfo;
LPPER_IO_DATA ioInfo;
DWORD flags = 0;
while (1) {
//在操作队列中获取IO完成的客户端信息 为什么第四个参数是ioInfo?因为ioInfo的地址和它第一个成员变量overlapped的地址相同
GetQueuedCompletionStatus(hComPort, &bytesTrans, (PULONG_PTR)&handleInfo,(LPOVERLAPPED*)&ioInfo, INFINITE);
cout << "获取完队列的信息" << endl;
cout << "客户端地址" << handleInfo->hclientSocket << endl;
cout << "线程 NO. " << GetCurrentThreadId() << endl;
sock = handleInfo->hclientSocket;
if (ioInfo->rwMode == READ) { //判断客户端是读还是写
cout << "message received!" << endl;
if (bytesTrans == 0) { //传输EOF时
closesocket(sock);
free(handleInfo);
free(ioInfo);
cout << "客户端关闭:" << sock << endl;
continue;
}
memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED)); //初始化时间对象的状态
ioInfo->wsaBuf.len = bytesTrans;
ioInfo->rwMode = WRITE;
//客户端socket 缓存数组地址 数组长度 保存实际字节数变量的地址 数据传输特性 时间状态 Routine函数
WSASend(sock, &(ioInfo->wsaBuf), 1, NULL, 0, &(ioInfo->overlapped), NULL);
cout << "发送完数据" << endl;
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);
cout << "接受完数据" << endl;
}
else {
cout << "message sent!" << endl;
free(ioInfo);
}
}
return 0;
}
windows下简单的IOCP模型迭代回声服务器实例
最新推荐文章于 2024-02-18 21:19:30 发布