代码实现:
INetServer.h
#pragma once
struct INetServer
{
virtual bool init() = 0;
virtual void run() = 0;
virtual void stop() = 0;
virtual bool uninit() = 0;
};
NetServer.h
#pragma once
#include "INetServer.h"
class CNetServer : public INetServer
{
public:
CNetServer();
virtual ~CNetServer();
virtual bool init() override;
virtual bool uninit() override;
};
NetServer.cpp
#include "NetServer.h"
#include <WinSock2.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
CNetServer::CNetServer()
{
}
CNetServer::~CNetServer()
{
}
bool CNetServer::init()
{
// 初始化网络库
WSADATA wsaData;
if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)) {
cerr << "WSAStartup() Failed" << endl;
return false;
}
return true;
}
bool CNetServer::uninit()
{
if (0 != WSACleanup()) {
cerr << "WSACleanup Failed()" << endl;
return false;
}
return true;
}
TCPServer.h
#pragma once
#include "NetServer.h"
#include <atomic>
class CTCPServerImp;
class CTCPServer final
: public CNetServer
{
public:
CTCPServer(char* pszIp, int nPort);
~CTCPServer();
virtual bool init() override;
virtual void run() override;
virtual void stop() override;
private:
CTCPServerImp* m_pImp;
};
TCPServer.cpp
#include "TCPServer.h"
#include "Macro.h"
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <iostream>
#include <queue>
#include <map>
#include <thread>
using namespace std;
#define MESSAGESIZE 1024
HANDLE CreateNewIOCompletionPort(DWORD dwNumberOfConcurrentThreads)
{
return CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, dwNumberOfConcurrentThreads);
}
bool AssociateDeviceWithCompletionPort(HANDLE hDevice, HANDLE hCompletionPort, DWORD dwCompletionKey)
{
HANDLE h = CreateIoCompletionPort(hDevice, hCompletionPort, dwCompletionKey, 0);
return h == hCompletionPort;
}
enum emSocketOperate
{
SOCKET_OPERATE_RECV
};
struct socketData
{
WSAOVERLAPPED overlapped;
WSABUF buf;
char sMessage[MESSAGESIZE];
DWORD dwBytes;
DWORD flag;
emSocketOperate socketOpType;
void Clear(emSocketOperate type)
{
memset(this, 0, sizeof(socketData));
buf.buf = sMessage;
buf.len = MESSAGESIZE;
socketOpType = type;
}
};
class CTCPServerImp
{
public:
CTCPServerImp(char* pszIp, int nPort)
: m_pszIP(nullptr)
, m_nPort(8888)
, m_svrSocket(INVALID_SOCKET)
, m_bStop(false)
, m_hIOCP(INVALID_HANDLE_VALUE)
{
if (pszIp != nullptr) {
int nLen = strlen(pszIp);
if (nLen > 8) {
m_pszIP = new char[nLen];
memcpy_s(m_pszIP, nLen, pszIp, nLen);
}
}
if (nPort > 0) {
m_nPort = nPort;
}
}
~CTCPServerImp()
{
if (m_svrSocket != INVALID_SOCKET) {
closesocket(m_svrSocket);
m_svrSocket = INVALID_SOCKET;
}
while (!m_queProcThread.empty()) {
auto pThread = m_queProcThread.front();
m_queProcThread.pop();
pThread->join();
delete pThread;
}
auto itor = m_mSock.begin();
for (; itor != m_mSock.end(); ++itor) {
closesocket(itor->first);
delete itor->second;
itor = m_mSock.erase(itor);
}
SAFE_DELETE(m_pszIP);
}
private:
bool init()
{
// 1、创建SOCKET
m_svrSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, WSA_FLAG_OVERLAPPED);
if (m_svrSocket == INVALID_SOCKET) {
cerr << "WSASocket()" << endl;
return false;
}
// 2、绑定端口
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(m_nPort);
if (m_pszIP == nullptr || strlen(m_pszIP) < 8) {
addr.sin_addr.s_addr = htonl(INADDR_ANY);
}
else {
inet_pton(AF_INET, m_pszIP, &addr.sin_addr);
}
// 此处std::bind函数和套接字bind函数冲突,需要通过作用域区分,::bind是匿名作用域
int nRet = ::bind(m_svrSocket, (SOCKADDR*)&addr, sizeof(addr));
if (0 != nRet) {
cerr << "bind()" << endl;
return false;
}
// 3、监听
nRet = listen(m_svrSocket, 10);
if (0 != nRet) {
cerr << "listen()" << endl;
return false;
}
}
void socketProcess()
{
DWORD dwBytes = -1;
SOCKET cSocket;
socketData *lpSocketData = nullptr;
DWORD dwMilliseconds = 1000;
while (!m_bStop) {
BOOL bOK = GetQueuedCompletionStatus(m_hIOCP, &dwBytes, (PULONG_PTR)&cSocket, (LPOVERLAPPED*)&lpSocketData, dwMilliseconds);
DWORD dwError = GetLastError();
if (bOK) {
// processs a successfully completed IO request
if (lpSocketData != nullptr && lpSocketData->socketOpType == SOCKET_OPERATE_RECV) {
if (dwBytes == 0) {
closesocket(cSocket);
delete lpSocketData;
m_mSock.erase(cSocket);
printf("%x\t:closed\n", (DWORD)cSocket);
}
else {
lpSocketData->sMessage[dwBytes] = '\0';
printf("%x\t:%s\n", (DWORD)cSocket, lpSocketData->sMessage);
lpSocketData->Clear(SOCKET_OPERATE_RECV);
WSARecv(cSocket, &lpSocketData->buf, 1, &lpSocketData->dwBytes, &lpSocketData->flag, &lpSocketData->overlapped, NULL);
}
}
}
else {
if (lpSocketData != nullptr) {
// process a failed completed IO request
// dwError contains the reason for failure
}
else {
if (dwError == WAIT_TIMEOUT) {
// Time-out while waiting for completed IO entry
}
else {
// Bad call to GetQueuedCompletionStatus
// dwError contains the reason for the bad call
}
}
}
}
}
void run()
{
if (m_svrSocket == INVALID_SOCKET) {
return;
}
// 创建完成端口
m_hIOCP = CreateNewIOCompletionPort(0);
// 创建完成端口处理线程池
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
for (int i = 0; i < sysInfo.dwNumberOfProcessors * 2; ++i) {
thread* pThread = new thread(&CTCPServerImp::socketProcess, this);
m_queProcThread.push(pThread);
}
// 接受连接及接收数据启动
SOCKADDR_IN clientAddr;
int nAddrLen = sizeof(clientAddr);
while (!m_bStop)
{
SOCKET cSocket = accept(m_svrSocket, (SOCKADDR*)&clientAddr, &nAddrLen);
if (cSocket != INVALID_SOCKET) {
char pszIP[20] = { 0 };
inet_ntop(AF_INET, &clientAddr.sin_addr, pszIP, 20);
printf("accept ip:%s port:%d\n", pszIP, ntohs(clientAddr.sin_port));
AssociateDeviceWithCompletionPort((HANDLE)cSocket, m_hIOCP, (DWORD)cSocket);
socketData* pData = new socketData;
pData->Clear(SOCKET_OPERATE_RECV);
WSARecv(cSocket, &pData->buf, 1, &pData->dwBytes, &pData->flag, &pData->overlapped, nullptr);
m_mSock[cSocket] = pData;
}
}
}
private:
// SOCKET
char* m_pszIP;
int m_nPort;
SOCKET m_svrSocket;
map<SOCKET, socketData*> m_mSock;
// 完成端口句柄
HANDLE m_hIOCP;
queue<thread*> m_queProcThread;
// 线程控制
std::atomic<bool> m_bStop;
friend class CTCPServer;
};
CTCPServer::CTCPServer(char* pszIp, int nPort)
{
m_pImp = new CTCPServerImp(pszIp, nPort);
}
CTCPServer::~CTCPServer()
{
SAFE_DELETE(m_pImp)
}
bool CTCPServer::init()
{
if (!CNetServer::init()) {
return false;
}
if (m_pImp != nullptr) {
m_pImp->init();
}
}
void CTCPServer::run()
{
thread tAccept(&CTCPServerImp::run, m_pImp);
tAccept.join();
}
void CTCPServer::stop()
{
m_pImp->m_bStop = true;
}
main.cpp
#include "TCPServer.h"
#include <iostream>
#include <windows.h>
int main(int argc, char** argv)
{
CTCPServer tcp(nullptr, 1234);
tcp.init();
tcp.run();
tcp.uninit();
return 0;
}
Macro.h
#ifndef __MACRO_H__
#define __MACRO_H__
#define SAFE_DELETE(ptr) if (ptr != nullptr) { delete ptr; ptr = nullptr; }
#define SAFE_DELETE_ARR(pArr) if (pArr != nullptr) { delete [] pArr; pArr = nullptr; }
#endif __MACRO_H__