目录
一:了解高并发服务器
二:服务器设计[Socket封装]
三:客户端设计[多个客户端使用一个服务器]
四:服务器和客户端之间通信 结果测试
一:了解高并发服务器
【Linux网络编程】- 高并发服务器框架设计
二:服务器设计[Socket封装]
SOCKET封装设计包含以下四个类
地址类设计:
SOCKET封装设计包含以下四个类
地址类设计:
#pragma once #include#include #include #include #include class CHostAddress { public: CHostAddress(char* ip, unsigned short port); ~CHostAddress(); char* getIp(); void setIp(char* ip); unsigned short getPort(); void setPort(unsigned short port); struct sockaddr_in getAddr_in(); struct sockaddr* getAddr(); int getLength(); private: char ip[16]; //保存ip地址 int length; //保存 sockaddr_in 结构体长度 unsigned short port; //端口号 struct sockaddr_in s_addr; };
#include "CHostAddress.h"
CHostAddress::CHostAddress(char* ip, unsigned short port)
{
memset(this->ip, 0, sizeof(this->ip));
strcpy(this->ip, ip);
this->port = port;
this->s_addr.sin_family = AF_INET;
this->s_addr.sin_port = htons(this->port);
this->s_addr.sin_addr.s_addr = inet_addr(this->ip);
this->length = sizeof(this->s_addr);
}
CHostAddress::~CHostAddress()
{
}
char* CHostAddress::getIp()
{
return this->ip;
}
void CHostAddress::setIp(char* ip)
{
strcpy(this->ip, ip);
}
unsigned short CHostAddress::getPort()
{
return this->port;
}
void CHostAddress::setPort(unsigned short port)
{
this->port = port;
}
sockaddr_in CHostAddress::getAddr_in()
{
return this->s_addr;
}
sockaddr* CHostAddress::getAddr()
{
return (struct sockaddr*)&(this->s_addr);
}
int CHostAddress::getLength()
{
return this->length;
}
socket基类设计 :
#pragma once #include#include #include #include class CBaseSocket { public: CBaseSocket(char* ip, unsigned short port); ~CBaseSocket(); void Start(); int getSocketFd(); virtual void Run() = 0; virtual void Stop() = 0; protected: int socketFd; };
#include "CBaseSocket.h"
CBaseSocket::CBaseSocket(char* ip, unsigned short port)
{
this->socketFd = 0;
}
CBaseSocket::~CBaseSocket()
{
}
void CBaseSocket::Start()
{
this->socketFd = socket(AF_INET, SOCK_STREAM, 0);
if (this->socketFd < 0)
{
perror("socket error");
}
this->Run();
}
int CBaseSocket::getSocketFd()
{
return this->socketFd;
}
TCP类设计 :
#pragma once #include#include "CBaseSocket.h" #include "CHostAddress.h" #include #include #include #include #include using namespace std; #define LISTEN_MAX_NUM 10 class CTcpServer : public CBaseSocket { public: CTcpServer(char* ip, unsigned short port); ~CTcpServer(); void Run(); void Stop(); CHostAddress* getAddress(); void setAddress(CHostAddress* address); private: CHostAddress* address; };
#include "CTcpServer.h"
CTcpServer::CTcpServer(char* ip, unsigned short port)
:CBaseSocket(ip, port)
{
this->address = new CHostAddress(ip, port);
}
CTcpServer::~CTcpServer()
{
}
void CTcpServer::Run()
{
int opt_val = 1;
int res = 0;
res = setsockopt(this->socketFd, SOL_SOCKET, SO_REUSEADDR, (const void*)&opt_val, sizeof(opt_val));
if (res == -1)
{
perror("setsockopt error");
}
res = bind(this->socketFd, this->address->getAddr(), this->address->getLength());
if (res == -1)
{
perror("bind error");
}
res = listen(this->socketFd, LISTEN_MAX_NUM);
if (res == -1)
{
perror("listen error");
}
cout << "Server start success socketFd = " << this->socketFd << endl;
}
void CTcpServer::Stop()
{
if (this->socketFd != 0)
{
close(this->socketFd);
this->socketFd = 0;
}
}
CHostAddress* CTcpServer::getAddress()
{
return this->address;
}
void CTcpServer::setAddress(CHostAddress* address)
{
this->address = address;
}
Epoll类设计:
#pragma once #include#include #include "CTcpServer.h" #define EPOLL_SIZE 5 using namespace std; class CEpollServer { public: CEpollServer(char* ip, unsigned short port); ~CEpollServer(); void Start(); private: int epollfd; int epollwaitefd; int acceptFd; char buf[1024]; struct epoll_event epollEvent; struct epoll_event epollEventArray[5]; CTcpServer* tcp; };
#include "CEpollServer.h"
CEpollServer::CEpollServer(char* ip, unsigned short port)
{
//初始化 TcpServer类
this->tcp = new CTcpServer(ip, port);
this->tcp->Start();
cout << "socketFd = " << this->tcp->getSocketFd() << endl;
//初始化数据成员
this->epollfd = 0;
this->epollwaitefd = 0;
this->acceptFd = 0;
bzero(this->buf, sizeof(this, buf));
//事件结构体初始化
bzero(&(this->epollEvent), sizeof(this->epollEvent));
//绑定当前准备好的sockedfd(可用网络对象)
this->epollEvent.data.fd = this->tcp->getSocketFd();
//绑定事件为客户端接入事件
this->epollEvent.events = EPOLLIN;
//创建epoll
this->epollfd = epoll_create(EPOLL_SIZE);
//将已经准备好的网络描述符添加到epoll事件队列中
epoll_ctl(this->epollfd, EPOLL_CTL_ADD, this->tcp->getSocketFd(), &(this->epollEvent));
}
CEpollServer::~CEpollServer()
{
}
void CEpollServer::Start()
{
while (1)
{
cout << "epoll wait client" << endl;
this->epollwaitefd = epoll_wait(this->epollfd, epollEventArray, EPOLL_SIZE, -1);
if (this->epollwaitefd < 0)
{
perror("epoll wait error");
}
for (int i = 0; i < this->epollwaitefd; i++)
{
//判断是否有客户端上线
if (epollEventArray[i].data.fd == this->tcp->getSocketFd())
{
cout << "网络_开始工作_等待客户端_上线" << endl;
this->acceptFd = accept(this->tcp->getSocketFd(), NULL, NULL);
cout << "acceptfd = " << this->acceptFd << endl;
//上线的客户端描述符是acceptfd 绑定事件添加到epoll
epollEvent.data.fd = this->acceptFd;
epollEvent.events = EPOLLIN; //EPOLLIN表示对应的文件描述符可以读
epoll_ctl(this->epollfd, EPOLL_CTL_ADD, this->acceptFd, &epollEvent);
}
else if (epollEventArray[i].events & EPOLLIN)
{
bzero(this->buf, sizeof(this->buf));
int res = read(epollEventArray[i].data.fd, this->buf, sizeof(this->buf));
if (res > 0)
{
cout << "服务器_收到 fd = " << epollEventArray[i].data.fd << " 送达数据: buf = " << this->buf << endl;
}
else if (res <= 0)
{
cout << "客户端 fd = " << epollEventArray[i].data.fd << " _掉线_" << endl;
close(epollEventArray[i].data.fd);
//从epoll中删除客户端描述符
epollEvent.data.fd = epollEvent.data.fd;
epollEvent.events = EPOLLIN;
epoll_ctl(this->epollfd, EPOLL_CTL_DEL, epollEventArray[i].data.fd, &epollEvent);
}
}
}
}
}
服务器主入口:
#include#include "CEpollServer.h" using namespace std; int main() { CEpollServer* epoll = new CEpollServer("192.168.75.128", 10086); epoll->Start(); return 0; }
三:客户端设计[多个客户端使用一个服务器]
客户端主入口:
#include#include #include #include #include #include #include #include using namespace std; int main() { int socketfd = 0; int acceptfd = 0; int len = 0; int res = 0; char buf[255] = { 0 };//初始化 //初始化网络 socketfd = socket(AF_INET, SOCK_STREAM, 0); if (socketfd == -1) { perror("socket error"); } else { struct sockaddr_in s_addr; //确定使用哪个协议族 ipv4 s_addr.sin_family = AF_INET; //填入服务器的ip地址 也可以是 127.0.0.1 (回环地址) s_addr.sin_addr.s_addr = inet_addr("192.168.75.128"); //10000以下是操作系统使用的,自己定义的端口号应该要是10000以后 s_addr.sin_port = htons(10086); len = sizeof(s_addr); //绑定ip地址和端口号 int res = connect(socketfd, (struct sockaddr*)&s_addr, len); if (res == -1) { perror("connect error"); } else { while (1) { cout << "我想说:" << endl; cin >> buf; write(socketfd, buf, sizeof(buf)); bzero(buf, sizeof(buf)); } } } return 0; }
四:服务器和客户端之间通信 结果测试
打开服务器,并运行两个客户端,可以实现简单的通信交流。



