3 代码实现
在VS2015中创建一个“Win32控制台应用程序”,并添加MFC的头文件,如图2所示。将该程序命名为“IOCP_Server”。
图2 添加MFC公共头文件
3.1 添加套接字头文件
在stdafx.h中添加套接字编程所需的头文件和动态库。
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
3.2 服务端套接字操作
对于服务端来说,在接收客户端连接之前,需要对套接字的操作包括初始化、创建、绑定和监听等。
3.2.1 初始化套接字
使用以下代码对套接字进行初始化
int ret;
WSADATA wsaData;
if ((ret = WSAStartup(0x0202, &wsaData)) != 0)
{
printf("WSAStartup 执行错误%d\n", ret);
return -1;
}
WSAStartup()函数的作用是对套接字进行初始化,在对套接字进行操作之前,必须要调用该函数。以上代码的表示将使用版本号为2.2的套接字标准。
3.2.2 创建套接字
在成功初始了套接字之后,调用WSASocket()函数创建套接字。
SOCKET sListen;
if ((sListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket()执行错误%d\n", WSAGetLastError());
WSACleanup();
return -1;
}
以上代码的WSASocket()函数中,SOCK_STREAM表示套接字的类型是流套接字,即TCP协议对应的套接字;WSA_FLAG_OVERLAPPED表示在创建的套接字上进行重叠I/O操作,对于完成端口模型,该参数必须设置为这个值。
3.2.3 绑定套接字
绑定套接字指的是将本机网络信息与创建的套接字进行绑定。以下代码通过bind()函数对套接字进行了绑定。
SOCKADDR_IN InternetAddr;
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);
if (bind(sListen, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind()执行错误 %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
以上代码中,SOCKADDR_IN结构用来表述本机的网络信息,PORT是一个定义的常量
#define PORT 12345
3.2.4 监听套接字
套接字的监听指的是服务端在套接字上等待客户端的连接。
if (listen(sListen, 5) == SOCKET_ERROR)
{
printf("listen()执行错误 %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
listen()函数的第二个参数5,表示在等待连接的队列中最大数为5。
3.3 创建完成端口
在对套接字的操作包括初始化、创建、绑定和监听之后,接下来就是创建完成端口。在“1 完成端口简介”中提到,创建的完成端口将会和与客户端通信的套接字关联。
if ((hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
{
printf("CreateIoCompletionPort()执行错误%d\n", WSAGetLastError());
return -1;
}
以上代码的作用是创建了一个完成端口,该完成端口的句柄保存在hComPort中,将该变量声明为全局变量:
HANDLE hComPort = NULL;