一. 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)