server.h
#ifndef SERVERDEMO_H
#define SERVERDEMO_H
#include <QObject>
#include <QTcpServer>
#include <QMap>
#include <QSqlDatabase> //數(shù)據(jù)庫管理類
#include <QSqlQuery> //執(zhí)行sql語句的類
#include <QSqlRecord> //數(shù)據(jù)庫記錄類
#include "TextMessage.h"
#include "txtmsgassembler.h"
#include "TxtMsgHandler.h"
class ServerDemo : public QObject
{
Q_OBJECT
QTcpServer m_server; //服務(wù)端類對象
QMap<QTcpSocket*, TxtMsgAssembler*> m_map;
TxtMsgHandler* m_handler;
QSqlDatabase db;
public:
ServerDemo(QObject* parent = NULL);
bool start(int port); //啟動(dòng)服務(wù)端
void stop(); //停止服務(wù)端
void setHandler(TxtMsgHandler* handler);//設(shè)置接口
~ServerDemo();
protected slots:
void onNewConnection(); //新客戶端連接槽函數(shù)
void onConnected(); //連接槽函數(shù)
void onDisconnected(); //斷連槽函數(shù)
void onDataReady(); //數(shù)據(jù)接收槽函數(shù)
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)
{
//判斷字節(jié)的數(shù)據(jù)庫對象中是否包含了要處理的數(shù)據(jù)庫,如果沒有包含則添加一個(gè)數(shù)據(jù)庫,否則直接打開
if( !db.contains("user.db") )
{
//添加一個(gè)數(shù)據(jù)庫,調(diào)用該類中的靜態(tài)成員函數(shù)
db = QSqlDatabase::addDatabase("QSQLITE");//sqlite3
//設(shè)置數(shù)據(jù)庫名字
db.setDatabaseName("user.db");
}
//打開數(shù)據(jù)庫
if( !db.open() )
{
qDebug() << "數(shù)據(jù)庫打開失敗" << endl;
return;
}
//使用sql語句進(jìn)行表的創(chuàng)建
QString sql = "create table if not exists user_info("
"username varchar(16) primary key,"
"password varchar(16),"
"status varchar(10),"
"level varchar(10))";
//執(zhí)行語句
QSqlQuery querry;
if( !querry.exec(sql) )
{
qDebug() << "表創(chuàng)建失敗失敗" << 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);//用字典容器,為每一個(gè)客戶端分配一個(gè)裝配器類對象
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);
}
}
}
//循環(huán)從緩存區(qū)讀取數(shù)據(jù)
void ServerDemo::onDataReady()
{
QTcpSocket* tcp = dynamic_cast<QTcpSocket*>(sender());
char buf[256] = {0};
int len = 0;
if( tcp != NULL )
{
//通過字典容器找到發(fā)送信息的客戶端,
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;
}
//開啟服務(wù)端
bool ServerDemo::start(int port)
{
bool ret = true;
if( !m_server.isListening() )
{
ret = m_server.listen(QHostAddress("127.0.0.1"), port);
}
return ret;
}
//停止服務(wù)端
void ServerDemo::stop()
{
if( m_server.isListening() )
{
m_server.close();
}
}
//設(shè)置接口
void ServerDemo::setHandler(TxtMsgHandler *handler)
{
m_handler = handler;
}
//服務(wù)端析構(gòu)
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; //協(xié)議消息裝配器
TxtMsgHandler* m_handler; //接口函數(shù)
protected slots:
void onConnected(); //連接事件槽函數(shù)
void onDisconnected(); //斷連事件槽函數(shù)
void onDataReady(); //消息事件槽函數(shù)
void onBytesWritten(qint64 bytes);
public:
ClientDemo(QObject* parent = NULL);
bool connectTo(QString ip, int port); //連接服務(wù)器
qint64 send(TextMessage& message); //發(fā)送協(xié)議消息
qint64 available(); //查看緩沖區(qū)數(shù)據(jù)個(gè)數(shù)
void setHandler(TxtMsgHandler* handler);
bool isValid(); //判斷客戶端狀態(tài)
void close(); //關(guān)閉客戶端
};
#endif // CLIENTDEMO_H
client.cpp
#include "ClientDemo.h"
#include <QHostAddress>
#include <QDebug>
//信號(hào)與槽的映射
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)));
}
//連接信號(hào)的槽函數(shù)
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);
}
}
//斷開連接的槽函數(shù)
void ClientDemo::onDisconnected()
{
m_assembler.reset(); //重置裝配類對象
if( m_handler != nullptr )
{
TextMessage dscn("DSCN", "");
m_handler->handle(m_client, dscn);
}
}
//接收數(shù)據(jù)的槽函數(shù)
void ClientDemo::onDataReady()
{
char buf[256] = {0};
int len = 0;
//循環(huán)讀取緩沖區(qū)中的字節(jié)流數(shù)據(jù)
while( (len = m_client.read(buf, sizeof(buf))) > 0 )
{
QSharedPointer<TextMessage> ptm = nullptr;
m_assembler.prepare(buf, len); //加入存儲(chǔ)容器
while( (ptm = m_assembler.assemble()) != nullptr )//循環(huán)裝配協(xié)議文本,直到?jīng)]有文本可以裝配
{
if( m_handler != nullptr )
{
m_handler->handle(m_client, *ptm);
}
}
}
}
void ClientDemo::onBytesWritten(qint64 bytes)
{
(void)bytes;
}
//同步的方式連接服務(wù)端
bool ClientDemo::connectTo(QString ip, int port)
{
m_client.connectToHost(ip, port);
return m_client.waitForConnected();
}
//以協(xié)議消息為單位發(fā)送數(shù)據(jù)
qint64 ClientDemo::send(TextMessage& message)
{
QByteArray ba = message.serialize();
return m_client.write(ba.data(), ba.length());
}
//查看緩沖區(qū)的數(shù)據(jù)長度
qint64 ClientDemo::available()
{
return m_client.bytesAvailable();
}
void ClientDemo::setHandler(TxtMsgHandler *handler)
{
m_handler = handler;
}
//查看客戶端狀態(tài)
bool ClientDemo::isValid()
{
return m_client.isValid();
}
//關(guān)閉客戶端
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();
}
階段性效果圖
文章來源地址http://www.zghlxwxcb.cn/news/detail-728316.html
文章來源:http://www.zghlxwxcb.cn/news/detail-728316.html
到了這里,關(guān)于QT聊天室階段性記錄(完善中:注冊功能,數(shù)據(jù)庫存儲(chǔ))的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!