window网络编程 - select模型(实践篇)

一. main.cpp

include <iostream>
using namespace std;

#include "CWinNetStartup.h"
#include "CSelectModel.h"

#define PrintError( szNote )\
	cout<< szNote << " Error : "<<WSAGetLastError()<<endl\

SOCKET InitServer(int nPort);

CNetStartup Instance;

int main()
{
	SOCKET sockListen = InitServer(1234);
	CSelectModel netModel(enServer);
	netModel.AddServiceSocket(sockListen);
	netModel.EvenntWait();
	return 0;
}

SOCKET InitServer(int nPort){
	SOCKET sockListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (INVALID_SOCKET == sockListen){
		PrintError(" socket ");
		return -1;
	}

	sockaddr_in serverAddr = { 0 };
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(nPort);
	serverAddr.sin_addr.S_un.S_addr = ADDR_ANY;
	int nLen = sizeof serverAddr;
	int nRet = ::bind(sockListen, (sockaddr*)&serverAddr, nLen);
	if(nRet != 0){
		PrintError(" Bind ");
		return -1;
	}

	listen(sockListen, 5);

	return sockListen;
}

二. Select 模型逻辑代码

​ 2.1 CSelectModel.h

#pragma once

enum EUsage
{
	enServer,
	enClient
};

class CSelectModel
{
public:
	CSelectModel(EUsage enUage);
	~CSelectModel();

	void EvenntWait();
	void AddServiceSocket(SOCKET sockListen);

private:
	void OnAccept();
	void OnRead(SOCKET s);
	void EnumEvent(fd_set& readFd, fd_set& exceptFd);

private:
	EUsage	m_enUsage;
	fd_set m_socketFd;
	//服务socket 服务端对应listensocket 客户端为connectsocket
	SOCKET m_serviceSocket; 
};


​ 2.2 CSelectModel.cpp

#include "CSelectModel.h"

CSelectModel::CSelectModel(EUsage enUage )
	:m_enUsage(enUage)
{
	FD_ZERO(&m_socketFd);
}


CSelectModel::~CSelectModel()
{
}

//运行于IO线程内部
void CSelectModel::EvenntWait() {
	fd_set readFd;
	fd_set exceptFd;
	FD_ZERO(&readFd);
	FD_ZERO(&exceptFd);
	int nRet = 0;
	while (true) {
		readFd = m_socketFd;
		exceptFd = m_socketFd;
		nRet = select(
			0, &readFd, NULL, &exceptFd, NULL);
		if (nRet <= 0) {
			cout << "select error : " << WSAGetLastError() << endl;
		}
		EnumEvent(readFd, exceptFd);
	}
}

void CSelectModel::AddServiceSocket(SOCKET s) {
	m_serviceSocket = s;
	FD_SET(s, &m_socketFd);
}

void CSelectModel::EnumEvent(fd_set& readFd, fd_set& exceptFd) {
	for (int i = 0; i < m_socketFd.fd_count; i++) {
		SOCKET s = m_socketFd.fd_array[i];
		if (FD_ISSET(s, &exceptFd)) {
			closesocket(s);
			FD_CLR(s, &m_socketFd);
			cout << "something error occured !!!! : " << WSAGetLastError() << endl;
			return;
		}
		if (FD_ISSET(s, &readFd)) {
			if (m_enUsage == enServer) {
				if (s == m_serviceSocket) {
					OnAccept();
				}
				else {
					OnRead(s);
				}
			}
			else{
				OnRead(s);
			}
		}
	}
}

void CSelectModel::OnAccept() {
	SOCKADDR_IN remoteAddr = { 0 };
	int nLen = sizeof remoteAddr;
	SOCKET cliSocket = accept(m_serviceSocket, (SOCKADDR*)&remoteAddr, &nLen);
	if (cliSocket == INVALID_SOCKET) {
		cout << "Accept something error occured !!! : " << WSAGetLastError();
		closesocket(cliSocket);
	}
	if (m_socketFd.fd_count > FD_SETSIZE) {
		//路由只框架处理 TODO :
		return;
	}
	FD_SET(cliSocket, &m_socketFd);
	//路由只框架处理 TODO :
}

void CSelectModel::OnRead(SOCKET s) {
	char szBuff[1024] = "";
	int nLen = recv(s, szBuff, 1024, 0);
	if (nLen <= 0) {
		cout << "Recv socmething error occured !!! : " << WSAGetLastError() << endl;
		closesocket(s);
		return;
	}
	//路由到框架层处理 TODO :
	cout << " recv msg : " << szBuff << endl;
}

三 . 辅助类

​ CNetStartup

//网络库初始化相关工作
class CNetStartup
{
public:
	CNetStartup() {
#ifdef _WIN32
		WSADATA wd = { 0 };
		WSAStartup(MAKEWORD(2, 2), &wd);
#endif // _WIN32
	}
	~CNetStartup(){
#ifdef _WIN32
		WSACleanup();
#endif // _WIN32
	}
};

pch.h (vs2017) 以前版本 stdafx.h

#include <iostream>
#include <winsock2.h>
using namespace std;

本人目前正在一步步写一套完整的跨平台网络服务器框架,如果有对网络感兴趣的小伙伴,大家可以一起交流学习!!!!( QQ 2419380858)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值