IOCP思维导图:
1.服务器端
#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>#include <process.h>#include <winsock2.h>#include <windows.h>#pragma comment(lib,"ws2_32.lib");
//加载ws2_32.dll#define BUF_SIZE 100#define READ 3#define WRITE 5typedef 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;
unsigned int WINAPI EchoThreadMain(LPVOID CompletionPortIO);
void ErrorHandling(char *message);
SOCKET ALLCLIENT[100];
int clientcount = 0;
HANDLE hMutex;
//互斥量int main(int argc, char* argv[]){
hMutex = CreateMutex(NULL, FALSE, NULL);
//创建互斥量 WSADATA wsaData;
HANDLE hComPort;
SYSTEM_INFO sysInfo;
LPPER_IO_DATA ioInfo;
LPPER_HANDLE_DATA handleInfo;
SOCKET hServSock;
SOCKADDR_IN servAdr;
int i;
DWORD recvBytes = 0,flags = 0;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) ErrorHandling("WSAStartup() error!");
hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
//创建CP对象 GetSystemInfo(&sysInfo);
//获取当前系统的信息 for (i = 0;
i < sysInfo.dwNumberOfProcessors;
i++) _beginthreadex(NULL, 0, EchoThreadMain, (LPVOID)hComPort, 0, NULL);
//创建=CPU个数的线程数 hServSock = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);
//不是非阻塞套接字,但是重叠IO套接字。 memset(&servAdr, 0, sizeof(servAdr));
servAdr.sin_family = AF_INET;
servAdr.sin_addr.s_addr = htonl(INADDR_ANY);
servAdr.sin_port = htons(1234);
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));
//和重叠IO一样 handleInfo->hClntSock = hClntSock;
//存储客户端套接字 WaitForSingleObject(hMutex, INFINITE);
//线程同步 ALLCLIENT[clientcount++] = hClntSock;
//存入套接字队列 ReleaseMutex(hMutex);
memcpy(&(handleInfo->clntAdr), &clntAdr, addrLen);
CreateIoCompletionPort((HANDLE)hClntSock, hComPort, (DWORD)handleInfo, 0);
//连接套接字和CP对象 //已完成信息将写入CP对象 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;
//和重叠IO一样 ioInfo->rwMode = READ;
//读写模式 WSARecv(handleInfo->hClntSock, &(ioInfo->wsaBuf),//非阻塞模式 1, &recvBytes, &flags, &(ioInfo->overlapped), NULL);
}
CloseHandle(hMutex);
//销毁互斥量 return 0;
}
unsigned int 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,//确认“
已完成”
的I/O!! (LPDWORD)&handleInfo, (LPOVERLAPPED*)&ioInfo, INFINITE);
//INFINITE使用时,程序将阻塞,直到已完成的I/O信息写入CP对象 sock = handleInfo->hClntSock;
//客户端套接字 if (ioInfo->rwMode == READ)//读写模式(此时缓冲区有数据) {
puts("message received!");
if (bytesTrans == 0) // 连接结束 {
WaitForSingleObject(hMutex, INFINITE);
//线程同步 closesocket(sock);
int i = 0;
while (ALLCLIENT[i] == sock){
i++;
}
ALLCLIENT[i] = 0;
//断开置0 ReleaseMutex(hMutex);
free(handleInfo);
free(ioInfo);
continue;
}
int i = 0;
for (;
i < clientcount;
i++) {
if (ALLCLIENT[i] != 0)//判断是否为已连接的套接字 {
if (ALLCLIENT[i] != sock) {
LPPER_IO_DATA newioInfo;
newioInfo = (LPPER_IO_DATA)malloc(sizeof(PER_IO_DATA));
//动态分配内存 memset(&(newioInfo->overlapped), 0, sizeof(OVERLAPPED));
strcpy(newioInfo->buffer, ioInfo->buffer);
//重新构建新的内存,防止多次释放free newioInfo->wsaBuf.buf = newioInfo->buffer;
newioInfo->wsaBuf.len = bytesTrans;
newioInfo->rwMode = WRITE;
WSASend(ALLCLIENT[i], &(newioInfo->wsaBuf),//回声 1, NULL, 0, &(newioInfo->overlapped), NULL);
}
else {
memset(&(ioInfo->overlapped), 0, sizeof(OVERLAPPED));
ioInfo->wsaBuf.len = bytesTrans;
ioInfo->rwMode = WRITE;
WSASend(ALLCLIENT[i], &(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);
}
</windows.h></winsock2.h></process.h></stdlib.h></stdio.h>
2.客户端
#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <stdlib.h>#include <string.h>#include <windows.h>#include <process.h> #define BUF_SIZE 1000#define NAME_SIZE 20#pragma comment(lib, "ws2_32.lib") //加载 ws2_32.dll unsigned WINAPI SendMsg(void * arg);
//发送信息函数unsigned WINAPI RecvMsg(void * arg);
//接受信息函数void ErrorHandling(char * msg);
//错误返回函数int haveread = 0;
char NAME[50];
//[名字]char ANAME[50];
char msg[BUF_SIZE];
//信息int main(int argc, char *argv[]){
printf("请输入网名:");
scanf("%s", NAME);
WSADATA wsaData;
SOCKET hSock;
SOCKADDR_IN servAdr;
HANDLE hSndThread, hRcvThread;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) ErrorHandling("WSAStartup() error!");
hSock = socket(PF_INET, SOCK_STREAM, 0);
memset(&servAdr, 0, sizeof(servAdr));
servAdr.sin_family = AF_INET;
servAdr.sin_addr.s_addr = inet_addr("127.0.0.1");
servAdr.sin_port = htons(1234);
if (connect(hSock, (SOCKADDR*)&servAdr, sizeof(servAdr)) == SOCKET_ERROR) ErrorHandling("connect() error");
int resultsend;
puts("Welcome to joining our chatting room!n");
sprintf(ANAME, "[%s]", NAME);
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();
system("pause");
return 0;
}
unsigned WINAPI SendMsg(void * arg) // send thread main{
SOCKET sock = *((SOCKET*)arg);
char name_msg[NAME_SIZE + BUF_SIZE];
char padd[2];
fgets(padd, 2, stdin);
//多余的'
n'
printf("n send message:");
while (1) {
{
fgets(msg, BUF_SIZE, stdin);
if (!strcmp(msg, "qn") || !strcmp(msg, "Qn")) {
closesocket(sock);
exit(0);
}
sprintf(name_msg, "[%s] %s", NAME, msg);
char numofmsg = strlen(name_msg) + '
0'
;
char newmsg[100];
newmsg[0] = numofmsg;
newmsg[1] = 0;
//第一个字符表示消息的长度 strcat(newmsg, name_msg);
int result = send(sock, newmsg, strlen(newmsg), 0);
if (result == -1)return -1;
//发送错误 }
}
return NULL;
}
unsigned WINAPI RecvMsg(void * arg) // read thread main{
SOCKET sock = *((SOCKET*)arg);
char name_msg[NAME_SIZE + BUF_SIZE];
int str_len = 0;
while (1) {
{
char lyfstr[1000] = {
0 }
;
int totalnum = 0;
str_len = recv(sock, name_msg, 1, 0);
//读取第一个字符!获取消息的长度 if (str_len == -1)//读取错误 {
printf("return -1n");
return -1;
}
if (str_len == 0)//读取结束 {
printf("return 0n");
return 0;
//读取结束 }
totalnum = name_msg[0] - '
0'
;
int count = 0;
do {
str_len = recv(sock, name_msg, 1, 0);
name_msg[str_len] = 0;
if (str_len == -1)//读取错误 {
printf("return -1n");
return -1;
}
if (str_len == 0) {
printf("return 0n");
return 0;
//读取结束 }
strcat(lyfstr, name_msg);
count = str_len + count;
}
while (count < totalnum);
lyfstr[count] = '