有哪些可以在线做app的网站有哪些问题/东莞做网站推广的公司

有哪些可以在线做app的网站有哪些问题,东莞做网站推广的公司,阿里巴巴网站图片怎么做,中国企业网站建设服务器架构:libevent 线程池 数据库:MySQL 有两张表:chat_user和chat_group,分别保存用户信息和群信息 在线用户和群的保存: struct User {std::string name;//账号(用户名struct bufferevent* bev;//客…

服务器架构:libevent + 线程池
在这里插入图片描述
数据库:MySQL
有两张表:chat_user和chat_group,分别保存用户信息和群信息

在这里插入图片描述

在这里插入图片描述
在线用户和群的保存:

struct User
{std::string name;//账号(用户名struct bufferevent* bev;//客户端对应的事件
};//保存在线用户信息
std::list<User> *online_user;
//保存所有群的信息
std::map<std::string,std::list<std::string>> *group_info;

在这里插入图片描述

ChatServer的初始化

在这里插入图片描述

ChatServer::ChatServer()
{//初始化事件集合this->base =event_base_new();//初始化数据库对象db = new DataBase();//初始化数据库表(chat_user,chat_group)if(!db->database_init_table()){std::cout<<"init table failure"<<std::endl;exit(1);}//初始化数据结构对象info = new ChatInfo();//初始化群信息:把群信息从数据库里读出来,放入mapserver_update_group_info();//初始化线程池thread_num = 3;cur_thread = 0;pool = new ChatThread[thread_num];for(int i=0;i<thread_num;i++){pool[i].start(info,db);}
}

初始化事件集合,放入监听事件

ChatServer::ChatServer()
{this->base =event_base_new();
}

ChatServer::listen()

下载libevent源码并查看:
在这里插入图片描述
进入/xx/usr/share/doc/libevent-dev/examples,可查看libevent使用示例。
在这里插入图片描述
查看hello-world.c
在这里插入图片描述
去头文件查看evconnlistener_new_bind的用法。
头文件都在/usr/include/中。
在这里插入图片描述
进入listener.h
在这里插入图片描述
在这里插入图片描述

struct evconnlistener *evconnlistener_new_bind(struct event_base *base,//事件集合evconnlistener_cb cb,//一旦有客户端连接,就会触发回调函数void *ptr,unsigned flags,int backlog,//监听队列里的容量const struct sockaddr *sa,int socklen
);

unsigned flags:说明里flags Any number of LEV_OPT_* flags
于是搜索LEV_OPT_,得如下结果
在这里插入图片描述
写代码:

//创建监听对象
void ChatServer::listen(const char* ip, int port)
{struct sockaddr_in server_info;memset(&server_info,0,sizeof(server_info));//清空server_info.sin_family = AF_INET;server_info.sin_addr.s_addr = inet_addr(ip);server_info.sin_port = htons(port);struct evconnlistener *listener=evconnlistener_new_bind(base,listener_cb,this,LEV_OPT_CLOSE_ON_FREE,5,(struct sockaddr*)&server_info,sizeof(server_info));if(listener == NULL){std::cout<<"evconnlistener_new_bind error"<<std::endl;exit(1);}//监听集合event_base_dispatch(base);//死循环,如果集合没有事件,退出//释放对象evconnlistener_free(listener);event_base_free(base);
}

查看回调函数listenner_cb的声明:
在这里插入图片描述
把光标放在这,按下shift+8(也就是*),然后next
在这里插入图片描述

listener_cb

在回调函数中打印客户端的ip和端口,方便调试。
关于listener_cb的this参数的说明

struct evconnlistener *listener=evconnlistener_new_bind(base,listener_cb,   this   ,LEV_OPT_CLOSE_ON_FREE,5,(struct sockaddr*)&server_info,sizeof(server_info));

因为listener_cb是个静态函数,而静态函数只能通过对象来调用普通成员函数,所以listener_cb不能直接调用server_alloc_enevt()。
所以传入this参数,通过this来调用。(因为参数是void*,所以记得先把this强转回来)

//回调函数,有客户端发起连接,会触发该函数
void ChatServer::listener_cb(struct evconnlistener *listener, evutil_socket_t fd,struct sockaddr *c, int socklen, void *arg)
{struct sockaddr_in *client_info = (struct sockaddr_in*)c;std::cout<<"[connection]";std::cout<<" client ip : " <<inet_ntoa(client_info->sin_addr);std::cout<<" port : " << client_info->sin_port<<std::endl;//创建事件,放入线程池ser->server_alloc_event(fd);
}

初始化数据库对象

查找头文件
在这里插入图片描述
包含头文件要把include后面都写上

#include<mysql/mysql.h>
class DataBase
{
private:MYSQL *mysql;std::mutex _mutex;
public:DataBase();~DataBase();bool database_connect();void database_disconnect();bool database_init_table();
}

构造函数不需要做什么。

DataBase::DataBase()
{
}

初始化数据库表

是否要一直打开数据库——取决于项目对数据库的使用频繁程度。
远程通信系统对数据库使用不频繁,所以不用时将数据库关闭。

连接数据库:

在这里插入图片描述
在命令行敲的所有命令都可以通过mysql_query()来执行
在这里插入图片描述
mysql_query()如果查询成功,返回0。如果出现错误,返回非0值。

建议先在在mysql中测试语句的可执行性,再写入代码:

mysql -u root -p登录mysql
在这里插入图片描述

set names utf8;

在这里插入图片描述
显示query 成功。

bool DataBase::database_connect()
{//初始化数据库句柄mysql = mysql_init(NULL);//分配堆内存//连接数据库mysql = mysql_real_connect(mysql, "localhost","root","root","chat_database",0,NULL,0);if(mysql==NULL){std::cout<<"mysql_real_connect error"<<std::endl;return false;}//设置编码格式   (防止中文乱码)if(mysql_query(mysql, "set names utf8;")!=0){std::cout<<"set names utf8 error"<<std::endl;return false;}return true;
}

断开数据库:

直接调用mysql_close()函数

void DataBase::database_disconnect()
{mysql_close(mysql);
}

初始化数据库表:

创建chat_group的sql语句:

create table if not exists chat_group(
groupname varchar(128),
groupowner varchar(128),
groupmember varchar(4096)
)charset utf8;

创建chat_user的sql语句

create table if not exists chat_user(
username varchar(128),
password varchar(128),
friendlist varchar(4096),
grouplist varchar(4096)
)charset utf8;

初始化数据库表:

bool DataBase::database_init_table()
{database_connect();const char* g="create table if not exists chat_group(groupname varchar(128),groupowner varchar(128),groupmember varchar(4096))charset utf8;";if(mysql_query(mysql,g)!=0){return false;}const char* u="create table if not exists chat_user(username varchar(128),password varchar(128),friendlist varchar(4096),grouplist varchar(4096))charset utf8;";if(mysql_query(mysql,u)!=0){return false;}database_disconnect();return true;
}

初始化数据结构对象

struct User
{std::string name;//账号(用户名struct bufferevent* bev;//客户端对应的事件
};class ChatInfo
{
private://保存在线用户信息std::list<User> *online_user;//保存所有群的信息std::map<std::string,std::list<std::string>> *group_info;//访问在线用户的锁std::mutex list_mutex;//访问群信息的锁std::mutex map_mutex;
public:ChatInfo();~ChatInfo();void list_update_group(std::string* ,int);void list_print_group();
};
ChatInfo::ChatInfo()
{online_user = new std::list<User>;group_info = new std::map<std::string,std::list<std::string>>;
}

初始化群信息

server_update_group_info

逻辑:从数据库获取群信息,然后写入list。
所以获取群信息的函数是属于DataBase的,写入list的函数时属于ChatInfo的

void ChatServer::server_update_group_info()
{//连接数据库if(!db->database_connect()){exit(1);}std::string groupinfo[1024];//最多1024个群int num = db->database_get_group_info(groupinfo);std::cout<<"group num : "<<num<<std::endl;//断开数据库db->database_disconnect();info->list_update_group(groupinfo,num);//info->list_print_group();//测试用
}

database_get_group_info

在这里插入图片描述
在这里插入图片描述
mysql_store_result()用于从服务器获取结果集并将其存储在客户端中以供检索和处理,返回值是MYSQL_RES*
在这里插入图片描述
mysql_fetch_row()用于逐行获取查询结果集中的数据,返回值是MYSQL_ROW
在这里插入图片描述
MYSQL_ROW是个数组
在这里插入图片描述
用竖线|间隔每个数据。

int DataBase::database_get_group_info(std::string *g)
{if(mysql_query(mysql,"select * from chat_group;")!=0){std::cout<<"select error"<<std::endl;return -1;}MYSQL_RES *res = mysql_store_result(mysql);if(res==NULL){std::cout<<"store result error"<<std::endl;return -1;}MYSQL_ROW r;int idx=0;while(r = mysql_fetch_row(res)){g[idx] += r[0];g[idx] +='|';g[idx] += r[2];//std::cout<<g[idx]<<std::endl;idx++;}mysql_free_result(res);return idx;
}

list_update_group()

按database_get_group_info中的格式,查找竖线|,已得到每个数据。

void ChatInfo::list_update_group(std::string* g, int size)
{int idx=0,start =0;std::string groupname,membername;std::list<std::string> l;for(int i=0;i<size;i++){idx = g[i].find('|');groupname = g[i].substr(0,idx);//std::cout<<groupname<<std::endl;start = idx +1;while(1)//idx查找竖线,找不到是-1{idx = g[i].find('|',idx+1); //从idx开始查找if(idx==-1)break;membername = g[i].substr(start,idx-start);l.push_back(membername);start = idx +1;}membername = g[i].substr(start,idx - start);l.push_back(membername);this->group_info->insert(std::pair<std::string,std::list<std::string>>(groupname,l));l.clear();}
}            

初始化线程池

class ChatThread
{
private:std::thread *_thread;std::thread::id _id;struct event_base *base;ChatInfo *info;DataBase *db;
public:ChatThread();~ChatThread();void start(ChatInfo *,DataBase *);void run();static void worker(ChatThread*);};

ChatThread()

ChatThread::ChatThread()
{_thread = new std::thread(worker,this);_id = _thread->get_id();//get_id()时线程标准库里的base = event_base_new();
}

回调函数worker

因为静态成员函数worker只能访问静态成员变量,不能访问普通成员变量,却可以通过对象调用普通成员函数,所以再写一个普通成员函数run,同时在构造时传入this参数以调用run

void ChatThread::worker(ChatThread *t)
{t->run();
}

run()

因为event_base_dispatch()当集合中无事件时自动退出,所以随便放一个事件进集合。
比如放一个定时器事件,查找示例:
在这里插入图片描述
在这里插入图片描述
查看main函数中的使用示例

在这里插入图片描述

写代码:

void ChatThread::run()
{//集合中放入一个定时器事件struct event timeout;struct timeval tv;//将事件与集合绑定//base是构造函数初始化的base//EV_PERSIST表示定时器永远都有用event_assign(&timeout, base, -1, EV_PERSIST, timeout_cb,this);evutil_timerclear(&tv);tv.tv_sec=3;event_add(&timeout,&tv);std::cout<<"--- thread "<<_id<<" start working ---"<<std::endl;event_base_dispatch(base);//死循环,当集合中没有事件的时候退出event_base_free(base);}
void ChatThread::timeout_cb(evutil_socket_t fd, short event, void *arg)
{ChatThread *t=(ChatThread *)arg;//std::cout<<"-- thread "<<t->thread_get_id()<<" is listening --"<<std::endl;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/671739.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ 动态规划 状态压缩DP 最短Hamilton路径

给定一张 n 个点的带权无向图&#xff0c;点从 0∼n−1 标号&#xff0c;求起点 0 到终点 n−1 的最短 Hamilton 路径。 Hamilton 路径的定义是从 0 到 n−1 不重不漏地经过每个点恰好一次。 输入格式 第一行输入整数 n 。 接下来 n 行每行 n 个整数&#xff0c;其中第 i 行…

网络基础(三)

网络层与数据链路层 1.网络层2.IP2.1 基本概念2.2 协议头格式2.3 网段划分2.4 特殊的IP地址2.5IP地址的数量限制2.6 私有IP地址和公网IP地址2.7 路由 3.数据链路层4.以太网&#xff08;MAC帧协议&#xff09;4.1 认识以太网4.2 以太网帧格式4.3 认识MAC地址4.4 对比理解MAC地址…

51 -25 Scene as Occupancy 3D占用作为场景表示 论文精读

本文阅读的文章是Scene as Occupancy&#xff0c;介绍了一种将物体表示为3D occupancy的新方法&#xff0c;以描述三维场景&#xff0c;并用于检测、分割和规划。 文章提出了OccNet和OpenOcc两个核心概念。 OccNet 3D占用网络是一种以多视图视觉为中心的方法&#xff0c;通过…

14.0 Zookeeper环球锁实现原理

全局锁是控制全局系统之间同步访问共享资源的一种方式。 下面介绍zookeeper如何实现全民锁&#xff0c;讲解他锁和共享锁两类全民锁。 排他锁 排他锁&#xff08;Exclusive Locks&#xff09;&#xff0c;又被称为写锁或独占锁&#xff0c;如果事务T1对数据对象O1加上排他锁…

#免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程

Mac电脑苹果芯片读写NTFS硬盘bash脚本 &#xff08;ntfs.sh脚本内容在本文最后面&#xff09; ntfs.sh脚本可以将Mac系统(苹果M系芯片)上的NTFS硬盘改成可读写的挂载方式&#xff0c;从而可以直接往NTFS硬盘写入数据。此脚本免费&#xff0c;使用过程中无需下载任何收费软件。…

C#在既有数组中插入另一个数组:Array.Copy方法 vs 自定义插入方法

目录 一、使用的方法 1.使用Array.Copy方法 2.Copy(Array, Int32, Array, Int32, Int32) 3. 使用自定义的方法 二、实例 1.示例1&#xff1a;使用Array.Copy方法 2.示例2&#xff1a;使用自定义的方法 一、使用的方法 1.使用Array.Copy方法 首先定义了一个名为InsertAr…

【 buuctf-面具下的 flag】

直接 binwalk 提取图片内容其中 zip 为伪加密&#xff08;如下图&#xff09;&#xff0c;在 macOS 上当我运行 binwalk -e 指令来提取图片中内容是&#xff0c;zip可以自动解压出来 flag.vmdk&#xff0c;不需要修改压缩源文件目录区的全局方式位标记值。 在 kali Linux 下&am…

RabbitMQ-4.MQ的可靠性

MQ的可靠性 4.MQ的可靠性4.1.数据持久化4.1.1.交换机持久化4.1.2.队列持久化4.1.3.消息持久化 4.2.LazyQueue4.2.1.控制台配置Lazy模式4.2.2.代码配置Lazy模式4.2.3.更新已有队列为lazy模式 4.MQ的可靠性 消息到达MQ以后&#xff0c;如果MQ不能及时保存&#xff0c;也会导致消…

立足智能存取解决方案|HEGERLS智能托盘四向车储存制动能量 实现能源回收

对于商业配送和工业生产的企业而言&#xff0c;如何能高效率、低成本进行低分拣、运输、码垛、入库&#xff0c;用以提升仓库空间的利用效率&#xff0c;是现在大多企业急需要解决的行业痛点。对此&#xff0c;为了解决上述痛点&#xff0c;近年来&#xff0c;物流仓储集成商、…

docker常用10条容器操作命令

Docker 中一些常用的容器操作命令&#xff0c;我们可以根据需要使用这些命令来管理和操作 Docker 容器。我们这次以Hell-world这个镜像为例来说明&#xff1a; 1. docker pull hello-world #拉取hell-world镜像 2. docker images # 查看本地拉取的镜像 3. docker run hello…

【python】绘制爱心图案

以下是一个简单的Python代码示例&#xff0c;它使用turtle模块绘制一个代表爱和情人节的心形图案。 首先&#xff0c;请确保计算机上安装了Python和turtle模块。然后&#xff0c;将以下代码保存到一个.py文件中&#xff0c;运行它就可以看到爱心图案的绘制过程。 import turt…

20240203在Ubuntu20.04.6下配置stable-diffusion-webui.git

20240203在Ubuntu20.04.6下配置stable-diffusion-webui.git 2024/2/3 11:55 【结论&#xff1a;在Ubuntu20.04.6下&#xff0c;生成512x512分辨率的图像&#xff0c;大概需要11秒钟&#xff01;】 前提条件&#xff0c;可以通过技术手段上外网&#xff01;^_首先你要有一张NVID…

2024清洁能源、环境与智慧城市国际研讨会(ISCEESC2024)

2024清洁能源、环境与智慧城市国际研讨会(ISCEESC2024) 会议简介 2024年清洁能源、环境与智慧城市国际研讨会&#xff08;ISCEESC2024&#xff09;将在中国丽江举行。本次会议主要围绕清洁能源、环境和智慧城市等研究领域&#xff0c;旨在为该研究领域的专家学者提供一个国际…

用云手机打造tiktok账号需要注意些什么?

随着tiktok平台的火热&#xff0c;越来越多的商家开始尝试更高效的tiktok运营方法。其中&#xff0c;tiktok云手机作为一种新科技引起了很多人的注意&#xff0c;那么用云手机运营tiktok需要注意些什么&#xff1f;下文将对此进行详细解析。 1. 不是所有的云手机都适合做tiktok…

【分享】如何运用数字I/O来保护继电器

1.简述 在开关系统中&#xff0c;短路或者是开路的情况下&#xff0c;由于存在着额外的电流或者是电压&#xff0c;继电器往往会过载。所有的继电器都有一个最大的承载电流和热切换功率&#xff0c;如果超出了这个范围&#xff0c;会增加继电器焊接在一起的风险&#xff0c;从…

项目02《游戏-10-开发》Unity3D

【完成本集功能后共享1-10集整套代码】 基于 项目02《游戏-09-开发》Unity3D &#xff0c; 任务&#xff1a;传送至其他场景&#xff0c; 首先在场景中加入传送门&#xff0c; 设置人物标签&#xff0c; using UnityEngine; using UnityEngine.SceneManagement; u…

树莓派4b连接WQ9201外置无线网卡命令行配置详解

树莓派4B连接WQ9201无线网卡 接线方式 蓝色的线来连接树莓派和WQ9201demo板&#xff0c;USB接树莓派的USB接口&#xff0c;microUSB一端接demo板靠近天线部分的microUSB口。 驱动和固件准备 驱动直接放在树莓派系统的任意目录&#xff0c;目前配置则是将驱动放在树莓派的主目…

《Git 简易速速上手小册》第1章:Git 基础(2024 最新版)

文章目录 1.1 Git 简介&#xff1a;版本控制的演变1.1.1 基础知识讲解1.1.2 重点案例&#xff1a;协作开发流程优化案例&#xff1a;功能开发与分支策略 1.1.3 拓展案例 1&#xff1a;代码审查与合并1.1.4 拓展案例 2&#xff1a;冲突解决 1.2 安装和配置 Git&#xff1a;首次设…

代码随想录算法训练营第41天 | 343.整数拆分 96.不同的二叉搜索树

整数拆分 dp数组的含义&#xff1a;dp[i] 表示将 i 拆分所能得到的最大乘积。递推公式&#xff1a;dp[i] max(dp[i], max(j * (i - j), j * dp[i - j]))。我们对 j 从1开始遍历&#xff0c;检验不同的拆分方式能产生的最大乘积。对于拆分方式的选择&#xff0c;要么拆成 j 和 …

Win32 SDK Gui编程系列之--ListView自绘OwnerDraw(续)

通过所有者绘制的列表视图(2) 所有者绘制列表视图的基础已在前一页中说明。本页将展示如何在所有者绘制列表视图中显示数据库表数据。 1、访问日志 正如在另一个页面中所述,本网站的访问日志目前是通过SQLite3数据库管理的。 以下是上述程序执行的结果。为…