您的位置:首页 > 其它

WSAEventSelect模型

2017-04-07 00:19 375 查看
vs2013:肯定可用,但完全没有注释

WSAEventSelect模型在等待时不占用cpu时间,所以比阻塞的socket通信要效率高

#include "stdafx.h"
#include<iostream>

#include"winsock2.h"

#pragma  comment(lib,"WS2_32.lib")

int main(int argc, char**argv)
{
SOCKET sockets[20];
WSAEVENT events[20];
int num = 0;

WSAData wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);

SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serverAddr;
serverAddr.sin_port = htons(3000);
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
::bind(server, (sockaddr*)&serverAddr, sizeof(sockaddr));
listen(server, 10);

WSAEVENT serverEvent = WSACreateEvent();
WSAEventSelect(server, serverEvent, FD_ACCEPT | FD_CLOSE);
sockets[num] = server;
events[num] = serverEvent;
num++;

while (true)
{
int rec = ::WSAWaitForMultipleEvents(num, events, false, WSA_INFINITE, false);
rec = rec - WSA_WAIT_EVENT_0;
WSANETWORKEVENTS evt;
::WSAEnumNetworkEvents(sockets[rec], events[rec], &evt);
if (evt.lNetworkEvents & FD_ACCEPT)
{
if (evt.iErrorCode[FD_ACCEPT_BIT] == 0)
{
SOCKET client = accept(sockets[rec], NULL, NULL);
WSAEVENT clientEvent = WSACreateEvent();
WSAEventSelect(client, clientEvent, FD_WRITE | FD_READ | FD_CLOSE);//accept接收的与其父套接字的网络事件相同并且使用同一个时间对象
sockets[num] = client;
events[num] = clientEvent;
num++;

}
}
else if (evt.lNetworkEvents & FD_READ)
{
if (evt.iErrorCode[FD_READ_BIT] == 0)
{
char buf[100] = { 0 };
recv(sockets[rec], buf, 99, 0);
buf[99] = '\0';
printf("%s\n", buf);
}
}
else if (evt.lNetworkEvents & FD_WRITE)
{
if (evt.iErrorCode[FD_WRITE_BIT] == 0)
{
char buf[100] = "server:server";
send(sockets[rec], buf, strlen(buf) + 1, 0);
printf("%s\n", buf);
}
}
else if (evt.lNetworkEvents & FD_CLOSE)
{
if (evt.iErrorCode[FD_CLOSE_BIT] == 0)
{
::closesocket(sockets[rec]);
for (size_t i = rec; i < num - 1; i++)
{
sockets[i] = sockets[i - 1];
events[i] = events[i - 1];
}
num--;
}
}
}

WSACleanup();

return 0;
}

为了纪念自己这个东西搞不懂,事件本来也是不懂,花了一天基本明白,但是还是有许多细节扣不了,感觉,如果要定时发送还是在FD_WRITE下直接开线程循环吧,WSAEventSelect模型你无法像用FD_READ一样用FD_WRITE

FD_WRITE事件只有在以下三种情况下才会触发

①client 通过connect(WSAConnect)首次和server建立连接时,在client端会触发FD_WRITE事件

②server通过accept(WSAAccept)接受client连接请求时,在server端会触发FD_WRITE事件

③send(WSASend)/sendto(WSASendTo)发送失败返回WSAEWOULDBLOCK,并且当缓冲区有可用空间时,则会触发FD_WRITE事件

①②其实是同一种情况,在第一次建立连接时,C/S端都会触发一个FD_WRITE事件。

主要是③这种情况:send出去的数据其实都先存在winsock的发送缓冲区中,然后才发送出去,如果缓冲区满了,那么再调用send(WSASend,sendto,WSASendTo)的话,就会返回一个 WSAEWOULDBLOCK的错误码,接下来随着发送缓冲区中的数据被发送出去,缓冲区中出现可用空间时,一个 FD_WRITE 事件才会被触发,这里比较容易混淆的是 FD_WRITE 触发的前提是缓冲区要先被充满然后随着数据的发送又出现可用空间,而不是缓冲区中有可用空间,

此处照搬,原因是这个是我找了一天中说的最清楚的,没有绕来绕去把他们自己都给绕晕的(有的看着真的蛮恶心,他们自己肯定也看不懂)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: