我是靠谱客的博主 优美小懒猪,最近开发中收集的这篇文章主要介绍一个基于C++的Tcp异步服务器,CentOS7 + MariaDB + libevent,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

模仿python的twisted方式,构建了一个基于C++的Tcp服务器。

一、开发环境的部署

1、操作系统为CentOS,我的版本是7.3.1611

2、安装C++编译器,我的版本是4.8.5

(1)yumlist gcc-c++

(2)yuminstall gcc-c++.x86_64

3、安装libevent网络框架,我的版本是2.1.8

(1)进入解压后的目录,执行

./configure -prefix=/usr

make

make install

(2)检查是否安装成功

ls -al /usr/lib | grep libevent

(3)安装libevent-devel

yum list libevent-devel

yum install –y libevent-devel.x86_64

(4)以下步骤可能是需要的

cp /usr/lib/libevent-2.1.so.6 /usr/lib64

4、安装配置MariaDB数据库,当前版本5.5.56

(1)yuminstall –y mariadb mariadb-server

(2)systemctlstart mariadb

(3)systemctlenable mariadb

(4)初设密码:mysql_secure_installation

--------安装mariadb-devel--------

(5)yumlist mariadb-devel

(6)yuminstall –y mariadb-devel.x86_64

5、下载安装cmake,当前版本3.10.0

进入解压后的目录执行:

./bootstrap

gmake

gmake install

6、执行mariaCpp类库需要用到mariadb-connector的头文件及相关定义,故先安装mariadb-connector,当前版本3.0.2

下载地址:点击打开链接

进入解压后的目录执行:

mkdir build

cd build

cmake ..

make –j8

7、将编译后产生的头文件拷贝到/usr/include/mysql文件夹中

cp ./include/*.h /usr/include/mysql

cp ./build/include/*.h/usr/include/mysql

8、mariaDB的C++库,下载地址是:点击打开链接

将mariaCpp类库中的两个文件夹:mariacpp(包含头文件)、src(包含实现文件)拷贝到项目文件夹。类库中部分编码好像不符合当前c++编译器规范的要求,需做适当改动。

9、Makefile的编写

target_exe: xxx1.cpp xxx2.cpp … xxxn.cpp
	g++ xxx1.cpp xxx2.cpp … xxxn.cpp 
	-o target_exe –levent –Wall 
`mysql_config --cflags --libs` 
-I/home/liuhui/dbtest  #假设mariaCpp存放在这个目录, 就是刚才第8步那两个文件夹的父文件夹

二、说明

我的服务器是为单位机关内部众多的消费机服务的,处理结构模仿 twisted 风格,一个 factory 对象服务于多个 protocol 客户端对象。程序从consumer.cpp开始

#include <libevent/myreactor.h>

int main(void){

	CFactory factory;
	
	if(!factory.Init()){
		return 1;
	}
	factory.Run();

	return 0;
}

mylibevent.cpp是对libevent做简单包装,便于我们在集中精力于业务层。如不熟悉,可能需要单独对这块做学习,本文不赘述。

myreactor.cpp里定义了factory和protocol,他向下调用libevent网络层、和mysql层(mariacpp),factory对象内包含了一个vector,用来保存众多客户端对象,当服务端需要主动向全部客户端发送消息时,就有用了。

#include <iostream>
#include "myreactor.h"
#include "mylibevent.h"
#include <global.h>
#include <tools.h>
#include <mariacpp/exception.hpp>
#include <mariacpp/uri.hpp>

#include "echo_dev.h"

CFactory::CFactory(){
	m_pConn = new MariaCpp::Connection;
	m_vProtocol = new std::vector<CProtocol*>;
}

void
CFactory::Release(){
	CMyLibEvent::Release();
	if(NULL != m_vProtocol){
		std::vector<CProtocol*>::iterator it;
    	for(it=m_vProtocol->begin(); it!=m_vProtocol->end(); it++){
        	if(NULL != (*it)){
            	delete (*it);
            	(*it) = NULL;
        	}
    	}
    	m_vProtocol->clear();
    	delete m_vProtocol;
    	m_vProtocol = NULL;
	}
	
    if(NULL != m_pConn){
    	m_pConn->close();
    	delete m_pConn;
    	m_pConn = NULL;
    }
}

CFactory::~CFactory(){
	Release();
}

bool
CFactory::Init(){

	try {
        m_pConn->connect(MariaCpp::Uri(URI), USER, PASSWD);
        m_pConn->set_character_set("utf8");
        std::clog << "Connection status: SUCESS" << std::endl;
        std::clog << "MySQL Stat: " << m_pConn->stat() << std::endl;

    } catch (MariaCpp::Exception &e) {
        //std::cerr << e << std::endl;
        e.print("connection");
        Release();
        return false;
    }
	return CMyLibEvent::Init(this);
}

void
CFactory::AddProtocol(CProtocol* p){
	m_vProtocol->push_back(p);
}

void
CFactory::DelProtocol(CProtocol* p){
	std::vector<CProtocol*>::iterator it;
	for(it=m_vProtocol->begin(); it!=m_vProtocol->end(); it++){
		if(NULL != (*it) && p == (*it)){
			delete (*it);
			(*it) = NULL;
			m_vProtocol->erase(it);
			break;
		}
	}
}
void
CFactory::DelProtocol(int nDevNo){
	std::vector<CProtocol*>::iterator it;
	for(it=m_vProtocol->begin(); it!=m_vProtocol->end(); it++){
		if(nDevNo == (*it)->GetDevNo()){
			delete (*it);
			(*it) = NULL;
			m_vProtocol->erase(it);
		}
	}
}

void
CFactory::Run()const{
	CMyLibEvent::Run();
}

CProtocol类的几个重要成员函数

// 对客户端写数据
void
CProtocol::Write(char* buf, int len){
	CMyLibEvent::Write(m_pBev, buf, len);
}

客户端首次连接,可以向其要求注册信息,对方回发注册信息后,可以根据规则判断其是否合法。如非法则切断。

void
CProtocol::ConnectionMade(){
	// 首次连接,向客户端要求注册
    char sz[27] = {0x97, 0x98, 0x00, 0x12, 0x01, 0x01, 0x00, (char)0xA4, 0x02, 0x00, 0x00, 0x00, 0x0C, 0x5A,
    				0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0x00};
    Write(sz, 27);
}

接收消息的函数,tcp包一定会存在粘包的问题,这里采用的方法比较简单,不考虑拼合。

void
CProtocol::DataReceived(char* buf, int nLen){

	int nIndex = 0;
	bool b = true;
	while(b){
		if(nIndex > nLen - 1){
			break;
		}
		if(0x97 != (u8)buf[nIndex] || 0x98 != (u8)buf[nIndex+1]){
			nIndex++;
		}
		else{
			char* req = buf + nIndex;
                        int nOrdLen = (((u8)req[2]) << 8) + ((u8)req[3]) + 8;
			//这里是一些业务验证代码,略过
			
			switch((u8)req[4]){
				// 心跳
				case(0xFD):{
					//todo
					nIndex += 8;
					break;
				}
				// 注册信息
				case(0x01):{
					//todo
					nIndex += nOrdLen;
					break;
				}
				// 请求系统时间
				case(0xF5):{
					//todo
					nIndex += nOrdLen;
					break;
				}
				// 请求服务器参数
				case(0xF6):{
					//todo
					nIndex += nOrdLen;
					break;
				}
				// 查询、消费
				case(0xF8):{
					//todo
					nIndex += nOrdLen;
					break;
				}
				// 上传消费记录
				case(0xF0):{
					//todo
					nIndex += nOrdLen;
					break;
				}
				default:{
					nIndex++;
					break;
				}
			}
		}
	}
}

另外还有一些工具类,工具函数,见工程文件点击打开链接

本人QQ: 25468865,加友请注明csdn

最后

以上就是优美小懒猪为你收集整理的一个基于C++的Tcp异步服务器,CentOS7 + MariaDB + libevent的全部内容,希望文章能够帮你解决一个基于C++的Tcp异步服务器,CentOS7 + MariaDB + libevent所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(68)

评论列表共有 0 条评论

立即
投稿
返回
顶部