Linux + C + epoll 实现高并发服务器搭建

目录

一:高并发 前后置服务器 架构

二:服务器框架搭建 基础类设计

三:客户端 基础设计

四:C/S对接测试


一:高并发 前后置服务器 架构

高并发服务器框架设计

二:服务器框架搭建 基础类设计

服务器搭建 封装设计包括有以下四个类

地址类设计

#pragma once
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>

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 <sys/types.h>     
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>

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<iostream>
#include "CBaseSocket.h"
#include "CHostAddress.h"
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>         
#include <sys/socket.h>

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 <sys/epoll.h>
#include <iostream>
#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 <iostream>
#include "CEpollServer.h"

using namespace std;

int main()
{
	CEpollServer* epoll = new CEpollServer("192.168.75.128", 10086);
	epoll->Start();
	return 0;
}

三:客户端 基础设计

epoll IO多路复用 能够使得一个服务器可以与多个客户端建立连接

客户端测试入口

#include <iostream>
#include <sys/types.h>          
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

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;
}

四:C/S对接测试

 打开服务器,并运行两个客户端,可以实现简单的通信交流

  • 16
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 27
    评论
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chenruhan_QAQ_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值