基于epoll和Qt的聊天室(2)
https://github.com/ITACHIhe/epoll_chat_room
这里开始写socket
首先创建一个普通类socket.h socket.cpp
首先先弄一个结构体,这个术语也叫做连接池
struct epoll_conncetion_pool
{
int fd;//保存对方套接字
struct sockaddr_in s_sockaddr;//保存对方地址信息用的
QString ID;//保存对方登录账号
bool islive;//是否断开
QString room;
QString name;
QString mima;
};
注:我这里的实现及其简单,应该实现成双向链表的手法,首先先分配好链表的内存,并且弄成消息头+包头+包体的格式,应用层保证不丢包粘包等(不过局域网丢包不太可能)。
单例模式的相关代码
private:
socket_server();//单例模式的写法
public:
static socket_server* getInstance()//单例模式的写法
{
if(server==nullptr)
{
server=new socket_server();//单例模式的写法
}
return server;
}
static socket_server* freeInstance()//单例模式的写法
{
return server;
}
public:
static socket_server* server;//单例模式的写法
就构造函数私有化,通过函数创建等,不懂可百度。
其他的成员变量定义太多就不写在这里了
就写几个重要的定义
epoll_conncetion_pool my_ol[10000];
这个数组模拟连接池,因为真正的商业写法的连接池及其复杂就先使用数组模拟
构造函数里面初始化
for(int i=0;i<10000;i++)
{
my_ol[i].fd=0;
my_ol[i].ID="";
my_ol[i].islive=false;
my_ol[i].room="";
my_ol[i].name="";
//my_ol[i].s_sockaddr=0;
}
socket的每一部分都使用该单例类的成员函数来实现,使用单例类的好处就是保证都是属于这个对象的,这种写法及其便利于写网络。
socket_start()函数
正常的socket服务器流程。
记得每一个都要写一个判断,以定位错误。
中间的套接字选项那里是为了time_wait情况。
listen那个511其实是未完成队列的大小,这个其实写多少随你的,我这里填的511是因为nginx源码这里是填511。
socket_rec()函数
这个函数是epoll代码代码的核心
上面都是一些信息的填写的初始化epoll.
handle()函数
这个函数是这篇服务器代码里的核心
简要
服务器收到的指令一般都为字符串,所以我们一般都会对字符串进行加密,最好还是类似于https非对称加密。这份代码比较简陋,仅供学习
这里是接收数据
这里是判断数据是否是申请账号,如果是就运行create_ID()函数创建ID等,并将ID返回,注意:QString要和char*转换
我这里是根据头部的几个字符来判断客户端的需求的,所以这里前几行就是去掉标识符。
这里的only_ID 是set容器来的,这样就保证不会重复,使不会出现同样的客户
下面就是判断,如果这个用户没有登录过,就给登录,否则就不给。还有就是判断账号是否正确。
fdset也是set来的,这个是后面模拟广播使用的
这里就是创建聊天记录的文件夹存放文件,并用xml库解析,我使用的是tinyxml库,感觉不如使用自带的。
这里fdset是所有的fd,也包括自己的,所以再弄个容器把自己的去掉,再for循环一个一个发,再通过连接池里的每一个对象的数据里的房间号判断发什么房间里的。
下面对面发前缀为00000的是我在客户端写的一个信号,当客户端关闭的时候,自动发送0000,就代表对面退出,其实还有许多类似的信号应该弄,这里简写了。关闭了就将连接池清零。