server.h
#ifndef SERVERDEMO_H
#define SERVERDEMO_H
#include <QObject>
#include <QTcpServer>
#include <QMap>
#include <QSqlDatabase> //数据库管理类
#include <QSqlQuery> //执行sql语句的类
#include <QSqlRecord> //数据库记录类
#include "TextMessage.h"
#include "txtmsgassembler.h"
#include "TxtMsgHandler.h"
class ServerDemo : public QObject
{
Q_OBJECT
QTcpServer m_server; //服务端类对象
QMap<QTcpSocket*, TxtMsgAssembler*> m_map;
TxtMsgHandler* m_handler;
QSqlDatabase db;
public:
ServerDemo(QObject* parent = NULL);
bool start(int port); //启动服务端
void stop(); //停止服务端
void setHandler(TxtMsgHandler* handler);//设置接口
~ServerDemo();
protected slots:
void onNewConnection(); //新客户端连接槽函数
void onConnected(); //连接槽函数
void onDisconnected(); //断连槽函数
void onDataReady(); //数据接收槽函数
void onBytesWritten(qint64 bytes);
};
#endif // SERVERDEMO_H
server.cpp
#include "ServerDemo.h"
#include <QHostAddress>
#include <QTcpSocket>
#include <QObjectList>
#include <QDebug>
ServerDemo::ServerDemo(QObject* parent) : QObject(parent), m_handler(nullptr)
{
//判断字节的数据库对象中是否包含了要处理的数据库,如果没有包含则添加一个数据库,否则直接打开
if( !db.contains("user.db") )
{
//添加一个数据库,调用该类中的静态成员函数
db = QSqlDatabase::addDatabase("QSQLITE");//sqlite3
//设置数据库名字
db.setDatabaseName("user.db");
}
//打开数据库
if( !db.open() )
{
qDebug() << "数据库打开失败" << endl;
return;
}
//使用sql语句进行表的创建
QString sql = "create table if not exists user_info("
"username varchar(16) primary key,"
"password varchar(16),"
"status varchar(10),"
"level varchar(10))";
//执行语句
QSqlQuery querry;
if( !querry.exec(sql) )
{
qDebug() << "表创建失败失败" << endl;
return;
}
connect(&m_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
}
void ServerDemo::onNewConnection()
{
QTcpSocket* tcp = m_server.nextPendingConnection();
TxtMsgAssembler* assembler = new TxtMsgAssembler();
m_map.insert(tcp, assembler);//用字典容器,为每一个客户端分配一个装配器类对象
connect(tcp, SIGNAL(connected()), this, SLOT(onConnected()));
connect(tcp, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
connect(tcp, SIGNAL(readyRead()), this, SLOT(onDataReady()));
connect(tcp, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));
if( m_handler != nullptr )
{
TextMessage msg("CONN", tcp->peerAddress().toString() + ":" + QString::number(tcp->peerPort()));
m_handler->handle(*tcp, msg);
}
}
void ServerDemo::onConnected()
{
}
void ServerDemo::onDisconnected()
{
QTcpSocket* tcp = dynamic_cast<QTcpSocket*>(sender());
if( tcp != nullptr )
{
delete m_map.take(tcp);
if( m_handler != nullptr )
{
TextMessage msg("DSCN", "");
m_handler->handle(*tcp, msg);
}
}
}
//循环从缓存区读取数据
void ServerDemo::onDataReady()
{
QTcpSocket* tcp = dynamic_cast<QTcpSocket*>(sender());
char buf[256] = {0};
int len = 0;
if( tcp != NULL )
{
//通过字典容器找到发送信息的客户端,
TxtMsgAssembler* assembler = m_map.value(tcp);
while( (len = tcp->read(buf, sizeof(buf))) > 0 )
{
if( assembler != nullptr )
{
QSharedPointer<TextMessage> ptm = nullptr;
assembler->prepare(buf, len);
while( (ptm = assembler->assemble()) != nullptr )
{
if( m_handler != nullptr )
{
m_handler->handle(*tcp, *ptm);
}
}
}
}
}
}
void ServerDemo::onBytesWritten(qint64 bytes)
{
(void)bytes;
}
//开启服务端
bool ServerDemo::start(int port)
{
bool ret = true;
if( !m_server.isListening() )
{
ret = m_server.listen(QHostAddress("127.0.0.1"), port);
}
return ret;
}
//停止服务端
void ServerDemo::stop()
{
if( m_server.isListening() )
{
m_server.close();
}
}
//设置接口
void ServerDemo::setHandler(TxtMsgHandler *handler)
{
m_handler = handler;
}
//服务端析构
ServerDemo::~ServerDemo()
{
const QObjectList& list = m_server.children();
for(int i=0; i<list.length(); i++)
{
QTcpSocket* tcp = dynamic_cast<QTcpSocket*>(list[i]);
if( tcp != NULL )
{
tcp->close();
}
}
const QList<TxtMsgAssembler*>& al = m_map.values();
for(int i = 0; i < al.length(); i++)
{
delete al.at(i);
}
}
server_main.cpp
#include <QCoreApplication>
#include "serverhandler.h"
#include "ServerDemo.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ServerHandler handler;
ServerDemo server;
server.setHandler(&handler);
server.start(8888);
return a.exec();
}
client.h
#ifndef CLIENTDEMO_H
#define CLIENTDEMO_H
#include <QObject>
#include <QTcpSocket>
#include "TextMessage.h"
#include "txtmsgassembler.h"
#include "TxtMsgHandler.h"
class ClientDemo : public QObject
{
Q_OBJECT
QTcpSocket m_client; //客户端对象
TxtMsgAssembler m_assembler; //协议消息装配器
TxtMsgHandler* m_handler; //接口函数
protected slots:
void onConnected(); //连接事件槽函数
void onDisconnected(); //断连事件槽函数
void onDataReady(); //消息事件槽函数
void onBytesWritten(qint64 bytes);
public:
ClientDemo(QObject* parent = NULL);
bool connectTo(QString ip, int port); //连接服务器
qint64 send(TextMessage& message); //发送协议消息
qint64 available(); //查看缓冲区数据个数
void setHandler(TxtMsgHandler* handler);
bool isValid(); //判断客户端状态
void close(); //关闭客户端
};
#endif // CLIENTDEMO_H
client.cpp
#include "ClientDemo.h"
#include <QHostAddress>
#include <QDebug>
//信号与槽的映射
ClientDemo::ClientDemo(QObject* parent) : QObject(parent), m_handler(nullptr)
{
connect(&m_client, SIGNAL(connected()), this, SLOT(onConnected()));
connect(&m_client, SIGNAL(disconnected()), this, SLOT(onDisconnected()));
connect(&m_client, SIGNAL(readyRead()), this, SLOT(onDataReady()));
connect(&m_client, SIGNAL(bytesWritten(qint64)), this, SLOT(onBytesWritten(qint64)));
}
//连接信号的槽函数
void ClientDemo::onConnected()
{
if( m_handler != nullptr )
{
TextMessage conn("CONN", m_client.peerAddress().toString() + ":" + QString::number(m_client.peerPort()));
m_handler->handle(m_client, conn);
}
}
//断开连接的槽函数
void ClientDemo::onDisconnected()
{
m_assembler.reset(); //重置装配类对象
if( m_handler != nullptr )
{
TextMessage dscn("DSCN", "");
m_handler->handle(m_client, dscn);
}
}
//接收数据的槽函数
void ClientDemo::onDataReady()
{
char buf[256] = {0};
int len = 0;
//循环读取缓冲区中的字节流数据
while( (len = m_client.read(buf, sizeof(buf))) > 0 )
{
QSharedPointer<TextMessage> ptm = nullptr;
m_assembler.prepare(buf, len); //加入存储容器
while( (ptm = m_assembler.assemble()) != nullptr )//循环装配协议文本,直到没有文本可以装配
{
if( m_handler != nullptr )
{
m_handler->handle(m_client, *ptm);
}
}
}
}
void ClientDemo::onBytesWritten(qint64 bytes)
{
(void)bytes;
}
//同步的方式连接服务端
bool ClientDemo::connectTo(QString ip, int port)
{
m_client.connectToHost(ip, port);
return m_client.waitForConnected();
}
//以协议消息为单位发送数据
qint64 ClientDemo::send(TextMessage& message)
{
QByteArray ba = message.serialize();
return m_client.write(ba.data(), ba.length());
}
//查看缓冲区的数据长度
qint64 ClientDemo::available()
{
return m_client.bytesAvailable();
}
void ClientDemo::setHandler(TxtMsgHandler *handler)
{
m_handler = handler;
}
//查看客户端状态
bool ClientDemo::isValid()
{
return m_client.isValid();
}
//关闭客户端
void ClientDemo::close()
{
m_client.close();
}
client_main.cpp
#include "MainwinUI.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWin w;
w.show();
return a.exec();
}
阶段性效果图
文章来源地址https://www.toymoban.com/news/detail-728316.html
文章来源:https://www.toymoban.com/news/detail-728316.html
到了这里,关于QT聊天室阶段性记录(完善中:注册功能,数据库存储)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!