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

【Windows网络编程】EventSelect网络模型

2017-10-19 12:58 417 查看
//解决select模型工作者线程时间片未充分利用的问题
#include <winsock2.h>
#include <stdio.h>
#define PORT 6000
#pragma comment (lib,"Ws2_32.lib")
SOCKET ArrSocket[1024] = { 0 };
WSAEVENT ArrEvent[1024] = { 0 };
DWORD dwTotal = 0;
DWORD dwIndex = 0;
int ClientNums = 0;         //标记已经链接了多少个客户端
BOOL WinSockInit()
{
WSADATA data = { 0 };
if (WSAStartup(MAKEWORD(2, 2), &data))
return FALSE;
if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2){
WSACleanup();
return FALSE;
}
return TRUE;
}
//工作者线程 怎么实现 将监听的socket以及客户端通信的socket 同时进行监控?
//怎么来节省时间的?(相对select)
DWORD WINAPI ListentThreadProc(LPARAM lparam)
{
char buf[1024] = { 0 };
SOCKET sockClient = INVALID_SOCKET;  //用于accept临时使用的socket
WSANETWORKEVENTS NetWorkEvent = { 0 };
while (true){
//ArrSocket[1];
//数组内任意一个wsaevent有信号了,api就返回。。
dwIndex = WSAWaitForMultipleEvents(dwTotal, ArrEvent, FALSE, 100, FALSE);
if (dwIndex == WSA_WAIT_TIMEOUT){
continue;
}
//如何知道是哪个socket出现了网络事件,deindex发生网络事件的socket数组下标
WSAEnumNetworkEvents(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], ArrEvent[dwIndex - WSA_WAIT_EVENT_0], &NetWorkEvent);

if (NetWorkEvent.lNetworkEvents&FD_ACCEPT){//如果第三位数据是1,代表有客户端进行连接
if (NetWorkEvent.iErrorCode[FD_ACCEPT_BIT] != 0)
{
continue;
}
sockClient = accept(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], NULL, NULL);
if (sockClient == INVALID_SOCKET)
continue;
//连接完成后,立即将客户端的socket保存到数据,同时新建event与socket建立关系
WSAEVENT newEvent = WSACreateEvent();
WSAEventSelect(sockClient, newEvent, FD_READ | FD_WRITE | FD_CLOSE);

for (;;);//检查数组内是否有空值,如果有就保存。。
ArrSocket[dwTotal] = sockClient;
ArrEvent[dwTotal] = newEvent;
++dwTotal;
++ClientNums;
}

if (NetWorkEvent.lNetworkEvents&FD_READ)    //说明有客户端向服务器发送数据 但这个数据还只在网卡上 没有到达程序buffer
{
if (NetWorkEvent.iErrorCode[FD_READ_BIT] != 0)
{
continue;
}
recv(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], buf, sizeof(buf), 0);
printf("Recv:%s\n", buf);
send(ArrSocket[dwIndex - WSA_WAIT_EVENT_0], buf, strlen(buf), 0);
}

if (NetWorkEvent.lNetworkEvents&FD_WRITE)   //说明程序-服务器准备向客户端发送信息了、、
{
if (NetWorkEvent.iErrorCode[FD_WRITE_BIT] != 0)
{
continue;
}
printf("Send somthing\n");
}

if (NetWorkEvent.lNetworkEvents&FD_CLOSE)   //表示有一个socket关闭了 是监听的还是通信的 不需要关心。。
{
if (NetWorkEvent.iErrorCode[FD_CLOSE_BIT] != 0)
{
continue;
}
closesocket(ArrSocket[dwIndex - WSA_WAIT_EVENT_0]);
ArrSocket[dwIndex - WSA_WAIT_EVENT_0] = 0;
}
}
}
int main()
{
WinSockInit();
SOCKET sockListen = INVALID_SOCKET;//服务器监听的socket
sockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockListen == INVALID_SOCKET)
{
printf("Creat Socket Error");
return -1;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_addr.S_un.S_addr = INADDR_ANY;
service.sin_port = htons(PORT);

if (bind(sockListen, (sockaddr*)&service, sizeof(service)) == SOCKET_ERROR)
{
printf("Bind Failed\n");
return -1;
}

//进行event select特有的操作
WSAEVENT ListenEvent = WSACreateEvent();
//把WSAEVENT与一个socket进行绑定没 告诉绑定的对象需要关注的事件有哪些
WSAEventSelect(sockListen, ListenEvent, FD_ACCEPT | FD_CLOSE);//仅关注两个事件,有客户端进行连接,需要关闭服务器监听的socket
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)ListentThreadProc, NULL, NULL, NULL);//创建一个子进程,用子进程来处理所有的socket上的事件

if (listen(sockListen, SOMAXCONN) == SOCKET_ERROR){
printf("Listen Error\n");
return -1;
}
ArrSocket[dwTotal] = sockListen;
ArrEvent[dwTotal] = ListenEvent;
++dwTotal;//标识总共有多少个用户已经连接 到这里数组保存的socket只有一个

system("pause");
if (sockListen != INVALID_SOCKET)
{
closesocket(sockListen);
}
WSACleanup();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  windows select 网络