WSAEventSelect服务端

本文介绍了一个使用WinSock进行网络编程的示例,包括服务器端和客户端的实现过程。服务器端通过初始化套接字、绑定地址、监听连接请求等步骤完成设置,并通过事件选择机制处理多个客户端连接。客户端则连接到指定的服务器地址并发送消息。
// 下载地址 https://download.youkuaiyun.com/download/u010907036/10284533
// InitSocket.h
#pragma once
#include <WinSock2.h>
#include <string>
using namespace std;

class InitSocket
{
private:
// 通信端口
int m_nPort;
// 服务器默认IP
string m_strDefaultServerIP;
// WSAStartup是否调用成功
bool m_bStartup;
// 是否会监听本机所有IP
bool m_bUseAddrAny;
SOCKET m_ServerSocket;
public :
InitSocket();
~InitSocket();
void SetPort(int& nPort);
int& const GetPort();
void SetServerIP(string& IP);
string& const GetServerIP();
bool& IsStartUp();
bool& StartUp();
void SetWhetherUseAddrAny(bool& use);
bool Bind();
bool Listen();
SOCKET& GetServerSocket();
};


// InitSocket.cpp

#include "stdafx.h"

#include "InitSocket.h"


InitSocket::InitSocket():m_nPort(6666),m_strDefaultServerIP("127.0.0.1"),m_bStartup(false), m_bUseAddrAny(true)

{

}


InitSocket::~InitSocket()

{

if (m_bStartup)

{

::WSACleanup();

}

}


void InitSocket::SetPort(int & nPort)

{

m_nPort = nPort;

}


int & const InitSocket::GetPort()

{

return m_nPort;

}


void InitSocket::SetServerIP(string & IP)

{

m_strDefaultServerIP = IP;

}


string & const InitSocket::GetServerIP()

{

return m_strDefaultServerIP;

}


bool & InitSocket::IsStartUp()

{

return m_bStartup;

}


bool & InitSocket::StartUp()

{

WSADATA wsa;

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

if (WSAGetLastError() == 0)

{

m_ServerSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (INVALID_SOCKET != m_ServerSocket)

{

m_bStartup = true;

}

}

return m_bStartup;

}


void InitSocket::SetWhetherUseAddrAny(bool & use)

{

m_bUseAddrAny = use;

}


bool InitSocket::Bind()

{

if (m_bStartup)

{

sockaddr_in serverInfo;

if (m_bUseAddrAny)

{

serverInfo.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

}

else

{

serverInfo.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

}

serverInfo.sin_family = AF_INET;

serverInfo.sin_port = htons(m_nPort);

::bind(m_ServerSocket, (const sockaddr*)&serverInfo, sizeof(serverInfo));

if (WSAGetLastError() == 0)

{

return true;

}

}

return false;

}


bool InitSocket::Listen()

{

::listen(m_ServerSocket, 5);

if (WSAGetLastError() == 0)

return true;

return false;

}


SOCKET & InitSocket::GetServerSocket()

{

return m_ServerSocket;

}


// main.cpp

// WSAEventSelect.cpp : 定义控制台应用程序的入口点。

//


#include "stdafx.h"

#include <iostream>

#include "InitSocket.h"

#include <Windows.h>


using namespace std;


int main()

{

InitSocket initSocket;

initSocket.StartUp();

if (initSocket.IsStartUp())

{

bool use = true;

initSocket.SetWhetherUseAddrAny(use);

if (initSocket.Bind())

{

if (initSocket.Listen())

{

SOCKET serverSocket = initSocket.GetServerSocket();


// 1.创建事件

HANDLE hEventListen = WSACreateEvent();


// 2.声明事件对象数组

WSAEVENT eventArr[WSA_MAXIMUM_WAIT_EVENTS];


// 3.声明和事件相关的套接字数组

SOCKET socketArr[WSA_MAXIMUM_WAIT_EVENTS];


// 4.时间对象计数器

int nEventCnt(0);

WSAEventSelect(serverSocket, hEventListen, FD_ACCEPT | FD_CLOSE);


eventArr[0] = hEventListen;

socketArr[0] = serverSocket;


++nEventCnt;



while (true)

{

// 得到受信号的事件对象的下标  这里不等待所有事件受信号,等待单个,时间无限大

int SingalEventIndex = ::WSAWaitForMultipleEvents(nEventCnt, eventArr, false, WSA_INFINITE,false);

int errorCode = WSAGetLastError();

if (SingalEventIndex == WSA_WAIT_IO_COMPLETION || SingalEventIndex == WSA_WAIT_TIMEOUT)

{

// 执行失败或者超时

break;

}


// 得到受信号对象在数组中的下标

int SingalEventArrIndex = SingalEventIndex - WSA_WAIT_EVENT_0;

// 取出和该事件对象关联的套接字

SOCKET SignalSocket = socketArr[SingalEventArrIndex];


WSANETWORKEVENTS netWorkEvents; // 发生的网络事件

::WSAEnumNetworkEvents(SignalSocket, eventArr[SingalEventArrIndex], &netWorkEvents);

// 如果是有新的连接并且没有出错

if ((netWorkEvents.lNetworkEvents & FD_ACCEPT) && netWorkEvents.iErrorCode[FD_ACCEPT_BIT] == 0)

{

if (nEventCnt >= WSA_MAXIMUM_WAIT_EVENTS)

{

// 超过了64 个事件对象

continue;

}


sockaddr_in clientInfo;

int len = sizeof(clientInfo);

SOCKET clientSocket = ::accept(SignalSocket, (sockaddr*)&clientInfo, &len);

if (WSAGetLastError() == 0)

{

// 新的连接成功  为该客户端套接字创建新的事件对象

WSAEVENT clientEvent = ::WSACreateEvent();

// 把新的事件对象加入

::WSAEventSelect(clientSocket, clientEvent, FD_READ | FD_WRITE | FD_CLOSE);


eventArr[nEventCnt] = clientEvent;

socketArr[nEventCnt++] = clientSocket;

cout << "收到来自 " << inet_ntoa(clientInfo.sin_addr) << " 的连接" << endl;//.S_un.S_addr


}

}

else if (netWorkEvents.lNetworkEvents & FD_READ &&  netWorkEvents.iErrorCode[FD_READ_BIT] == 0)

{

char Buf[512];

memset(Buf, 0, sizeof(char) * 512);

int nRecv = ::recv(SignalSocket, Buf, 512, 0);

if (nRecv > 0)

{

cout << "受到客户端信息: " << Buf << endl;

}


}

else if (netWorkEvents.lNetworkEvents & FD_CLOSE && netWorkEvents.iErrorCode[FD_CLOSE_BIT] == 0)

{

closesocket(socketArr[SingalEventArrIndex]);

for (int i = SingalEventArrIndex; i < nEventCnt; i++)

{

eventArr[i] = eventArr[i+1];

socketArr[i] = socketArr[i+1];

}

}

}

}

}

}

    return 0;

}




// TCP客户端测试

// Client.cpp : 定义控制台应用程序的入口点。

//


#include "stdafx.h"

#include <WinSock2.h>


int main()

{

WSADATA wsa;

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

if (WSAGetLastError() == 0)

{

SOCKET serverSocket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

sockaddr_in serverInfo;

serverInfo.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

serverInfo.sin_port = htons(6666);

serverInfo.sin_family = AF_INET;

::connect(serverSocket, (const sockaddr*)&serverInfo, sizeof(serverInfo));

int errCode = WSAGetLastError();

::send(serverSocket, "hello world", 11, 0);

errCode = WSAGetLastError();

{

getchar();

}


}

    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值