当然tcp方式的模型还有事件选择模型。
就是把所有的网络事件和我们的一个程序里定义的事件梆定。
这个有它的好处,可能可以让我们更好的写一个线程来管理
接收与发送。
现在来讲一下一个完成端口模型。
完成端口
一个完成端口其实就是一个通知队列,由操作系统把已经完成的重叠i/o请求的通知
放入其中。当某项i/o操作一旦完成,某个可以对该操作结果进行处理的工作者线程
就会收到一则通知。而套接字在被创建后,可以在任何时候与某个完成端口进行关
联。
步骤:
1、创建一个空的完成端口;
2、得到本地机器的cpu个数;
3、开启cpu*2个工作线程(又名线程池),全部都在等待完成端口的完成包;
4、创建tcp的监听socket,使用事件邦定,创建监听线程;
5、当有人连接进入的时候,将client socket保存到一个我们自己定义的关键键,
并把它与我们创建的完成端口关联;
6、使用wsarecv和wsasend函数投递一些请求,这是使用重叠i/o的方式;
7、重复5~6;
注:1、重叠i/o的方式中,接收与发送数据包的时候,一定要进行投递请求这是
它们这个体系结构的特点
当然,在完成端口方式中,不是直接使用的wsarecv和wsasend函数进行请求
的投递的。而是使用的readfile,write的方式
2、完成端口使用了系统内部的一些模型,所以我们只要按照一定的顺序调用就
可以完成了。
3、完成端口是使用在这样的情况下,有成千上万的用户连接的时候,它能够
保证性能不会降低。
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#define port 5150
#define data_bufsize 8192
//关键项
typedef struct
{
overlapped overlapped;
wsabuf databuf;
char buffer[data_bufsize];
dword bytessend;
dword bytesrecv;
} per_io_operation_data, * lpper_io_operation_data;
typedef struct
{
socket socket;
} per_handle_data, * lpper_handle_data;
dword winapi serverworkerthread(lpvoid completionportid);
void main(void)
{
sockaddr_in internetaddr;
socket listen;
socket accept;
handle completionport;
system_info systeminfo;
lpper_handle_data perhandledata;
lpper_io_operation_data periodata;
int i;
dword recvbytes;
dword flags;
dword threadid;
wsadata wsadata;
dword ret;
if ((ret = wsastartup(0x0202, &wsadata)) != 0)
{
printf("wsastartup failed with error %d\n", ret);
return;
}
//打开一个空的完成端口
if ((completionport = createiocompletionport(invalid_handle_value, null, 0, 0)) == null)
{
printf( "createiocompletionport failed with error: %d\n", getlasterror());
return;
}
// determine how many processors are on the system.
getsysteminfo(&systeminfo);
// 开启cpu个数的2倍个的线程
for(i = 0; i < systeminfo.dwnumberofprocessors * 2; i++)
{
handle threadhandle;
// create a server worker thread and pass the completion port to the thread.
if ((threadhandle = createthread(null, 0, serverworkerthread, completionport,
0, &threadid)) == null)
{
printf("createthread() failed with error %d\n", getlasterror());
return;
}
// close the thread handle
closehandle(threadhandle);
}
//打开一个服务器socket
if ((listen = wsasocket(af_inet, sock_stream, 0, null, 0,
wsa_flag_overlapped)) == invalid_socket)
{
printf("wsasocket() failed with error %d\n", wsagetlasterror());
return;
}
internetaddr.sin_family = af_inet;
internetaddr.sin_addr.s_addr = htonl(inaddr_any);
internetaddr.sin_port = htons(port);
if (bind(listen, (psockaddr) &internetaddr, sizeof(internetaddr)) == socket_error)
{
printf("bind() failed with error %d\n", wsagetlasterror());
return;
}
if (listen(listen, 5) == socket_error)
{
printf("listen() failed with error %d\n", wsagetlasterror());
return;
}
//开始接收从客户端来的连接