您的位置:首页 > 理论基础 > 计算机网络

windows下简单的IOCP模型迭代回声服务器实例

2017-04-25 16:04 363 查看
#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  socket IO复用 TCP iocp