多人在线聊天室,类似于咱们的QQ群,通过usr表记录注册过的用户,online表记录当前在线的用户
1.tcpser.h
2.tcpser.cpp
1.chat_box.h
2.login.h ----------------------------需要修改连接的ip和端口号
3.chat_box.cpp
4.login.cpp
----------------------------------tcpser.h----------------------------------
#ifndef TCPSER_H
#define TCPSER_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class TcpSer : public QObject
{
Q_OBJECT
public:
explicit TcpSer(QObject *parent = nullptr);
void start(void);
signals:
public slots:
void net_accpet();
void net_read();
// void update_online_count();
private:
QTcpServer *tcpser;
QTcpSocket *client; //当前响应的client
QList online_clientlist;
int usr_id = 0;
int online_id = 0;
};
#endif // TCPSER_H
----------------------------------tcpser.cpp----------------------------------
#include "tcpser.h"
TcpSer::TcpSer(QObject *parent) : QObject(parent)
{
//创建数据库
QSqlDatabase mydb = QSqlDatabase::addDatabase("QSQLITE");
mydb.setDatabaseName("user.db"); //设置数据库的名字
bool ok = mydb.open(); //打开数据库,不存在则创建
if(!ok){
qDebug()<<"open database failed";
}
//创建usr表
QString sql = "create table if not exists usr (ID text,name text,passwd text,status text)";
QSqlQuery query;
ok = query.exec(sql);
if(!ok){
qDebug()<<"create table failed";
}
//创建在线用户表
QString sql1 = "create table if not exists online (ID text,name text,ip text,port text)";
QSqlQuery query1;
ok = query1.exec(sql1);
if(!ok){
qDebug()<<"create table failed";
}
tcpser = new QTcpServer(this);
tcpser->listen(QHostAddress("0.0.0.0"),8080);
connect(tcpser,SIGNAL(newConnection()),this,SLOT(net_accpet()));//连接请求时执行
// QTimer *timer = new QTimer(this);
// //定时检查更新设备的网络状态
// connect(timer,SIGNAL(timeout()),this,SLOT(update_online_count()));
// timer->start(30000);
}
//void TcpSer::update_online_count()
//{
// QString text = "###online_num";
// QString online_num = QString::number(online_clientlist.size());
// text.append(online_num);
// client->write(text.toStdString().c_str()); // 发送在线人数
//}
void TcpSer::net_accpet()
{
client = tcpser->nextPendingConnection();//建立连接
QHostAddress cli_ip = client->peerAddress();
quint16 cli_port = client->peerPort();
QString ip = cli_ip.toString();
QString port = QString::number(cli_port);
qDebug()<<"connect a client ip:"<sender();
QTcpSocket *tcpclient = dynamic_cast(sender());
client = tcpclient;
//读取到client的数据
QString data = QString(tcpclient->readAll());
QStringList list;
QString name,passwd,status;
list = data.split("4tGkOMIzweAbPxrF");
int ret = list.size();
if(ret == 3)
{
//登陆
name = list[0];
passwd = list[1];
status = list[2]; //'0'---离线 '1'---在线
//数据库是否有该用户并且处于离线状态
QString sql = QString("select * from usr where name='%1' and passwd='%2' and status='%3'").arg(name,passwd,status);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"登陆验证:查询失败";
}
else
{
qDebug()<<"登陆验证:查询成功";
bool ok = query.next();
if(!ok)
{
//定位失败 无该用户或者该用户已登陆
qDebug()<<"无该用户或者该用户已登陆,登陆失败";
QString data = "###login false";
QByteArray ba;
ba.append(data);
char *c = ba.data();
client->write(c);
}
else
{
//数据库有用户并且处于离线状态
status = '1';
QString sql = QString("update usr set status='%2' where name='%1'").arg(name,status);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"登陆更新:失败";
}
else
{
qDebug()<<"登陆更新:成功";
//获取用户 ip port
QHostAddress cli_ip = client->peerAddress();
quint16 cli_port = client->peerPort();
QString ip = cli_ip.toString();
QString port = QString::number(cli_port);
QString data = "###login success";
QByteArray ba;
ba.append(data);
char *c = ba.data();
client->write(c);
online_clientlist.append(client); //放入容器
qDebug()<<"ip:"<write(text.toStdString().c_str()); // 发送在线人数
}
}
}
}
if(ret == 2)
{
//注册
//判断数据库是否存在该用户名
name = list[0];
passwd = list[1];
status = "0";
QString sql = QString("select * from usr where name='%1'").arg(name);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"查询失败";
}
if(ok)
{
qDebug()<<"查询成功";
bool ok = query.next();
if(!ok)
{
//用户不存在,注册新用户
++usr_id;
QString ID = QString::number(usr_id);
QString sql = QString("insert into usr values ('%1','%2','%3','%4')").arg(ID,name,passwd,status);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"执行插入失败";
--usr_id;
}
else
{
qDebug()<<"用户不存在";
qDebug()<<"执行插入成功";
const char *ch = "###registration success";
client->write(ch);
}
}
else
{
//用户存在
qDebug()<<"用户存在";
QString data = "###registration false";
QByteArray ba;
ba.append(data);
const char *c = ba.data();
client->write(c);
}
}
}
if(ret == 1)
{
//对话
QString data1 = data;
QString data2 = data;
QString data3 = data;
QString data4 = data;
QString data5 = data;
// QString data6 = data;
QString text1 = data1.mid(0,22);
QString text2 = data2.mid(0,13);
QString text3 = data3.mid(0,14);
QString text4 = data4.mid(0,9);
QString text5 = data5.mid(0,15);
// QString text6 = data6.mid(0,16);
if(text1 == "###super administrator")
{
//超级管理员发布消息<=========>server
for(int i = 0;i < online_clientlist.size();i++)
{
QString super_data;
super_data = data.replace("###super administrator","");
online_clientlist.at(i)->write(super_data.toStdString().c_str());
}
}
else if(text2 == "###i will off")
{
for(int i = 0;i < online_clientlist.size();i++)
{
if(online_clientlist.at(i) == client)
{
//client断开连接 对应status置0
//--->根据socket找到对应的ip port-->再根据 ip port 查online中对应的name--->删除在线用户数据库中的对应用户--->然后再将usr中name对应的
QHostAddress cli_ip = online_clientlist.at(i)->peerAddress();
quint16 cli_port = online_clientlist.at(i)->peerPort();
QString ip = cli_ip.toString();
QString port = QString::number(cli_port);
QString sql = QString("select * from online where ip='%1' and port='%2'").arg(ip,port);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"client断开 查找online失败";
}
else
{
query.next();
QString name = query.value(1).toString();
QString status = "0";
QString sql = QString("update usr set status='%2' where name='%1'").arg(name,status);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"client断开usr更新失败";
}
else
{
QString off_ip,off_port;
off_ip = ip;
off_port = port;
qDebug()<<"client off "<<"ip:"<write(data.toStdString().c_str());
// online_clientlist.at(i)->deleteLater();
// qDebug()<根据socket找到对应的ip port-->再根据 ip port 查online中对应的name--->删除在线用户数据库中的对应用户--->然后再将usr中name对应的
QHostAddress cli_ip = online_clientlist.at(i)->peerAddress();
quint16 cli_port = online_clientlist.at(i)->peerPort();
QString ip = cli_ip.toString();
QString port = QString::number(cli_port);
QString sql = QString("select * from online where ip='%1' and port='%2'").arg(ip,port);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"client断开 查找online失败";
}
else
{
query.next();
QString name = query.value(1).toString();
QString status = "0";
QString sql = QString("update usr set status='%2' where name='%1'").arg(name,status);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"client断开usr更新失败";
}
else
{
QString off_ip,off_port;
off_ip = ip;
off_port = port;
qDebug()<<"client off "<<"ip:"<write(text.toStdString().c_str()); // 发送在线人数
}
}
else if(text5 == "#####i will off")
{
for(int i = 0;i < online_clientlist.size();i++)
{
if(online_clientlist.at(i) == client)
{
//client断开连接 对应status置0
//--->根据socket找到对应的ip port-->再根据 ip port 查online中对应的name--->删除在线用户数据库中的对应用户--->然后再将usr中name对应的
QHostAddress cli_ip = online_clientlist.at(i)->peerAddress();
quint16 cli_port = online_clientlist.at(i)->peerPort();
QString ip = cli_ip.toString();
QString port = QString::number(cli_port);
QString sql = QString("select * from online where ip='%1' and port='%2'").arg(ip,port);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"client断开 查找online失败";
}
else
{
query.next();
QString name = query.value(1).toString();
QString status = "0";
QString sql = QString("update usr set status='%2' where name='%1'").arg(name,status);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"client断开usr更新失败";
}
else
{
// QString off_ip,off_port;
// off_ip = ip;
// off_port = port;
// qDebug()<<"client off "<<"ip:"<write(text.toStdString().c_str()); // 发送在线人数
}
}
}
}
}
}
else
{
for(int i = 0;i < online_clientlist.size();i++)
{
if(online_clientlist.at(i) == client) //其中一个在线client发送消息 判断等于自己 查表获取自己的name
{
QHostAddress c_ip = online_clientlist.at(i)->peerAddress();
quint16 c_port = online_clientlist.at(i)->peerPort();
QString chat_ip = c_ip.toString();
QString chat_port = QString::number(c_port);
QString data1 = data;
qDebug()<<"ip:"<peerAddress(); //当前的
quint16 c_port = client->peerPort();
QString chat_ip = c_ip.toString();
QString chat_port = QString::number(c_port);
QString sql = QString("select * from online where ip='%1' and port='%2'").arg(chat_ip,chat_port);
QSqlQuery query;
bool ok = query.exec(sql);
if(!ok)
{
qDebug()<<"查找该client的name失败";
}
else
{
query.next();
QString name = query.value(1).toString();
QString client_chat = name;
client_chat.append(":");
client_chat.append(data);
online_clientlist.at(i)->write(client_chat.toStdString().c_str());
}
}
}
}
}
}
void TcpSer::start()
{
qDebug()<<"Server start";
}
----------------------------------chat_box.h----------------------------------
#ifndef CHAT_BOX_H
#define CHAT_BOX_H
#include
#include
#include
#include
#include
#include
#include "login.h"
#include
namespace Ui {
class chat_box;
}
class chat_box : public QWidget
{
Q_OBJECT
public:
explicit chat_box(QWidget *parent = 0);
~chat_box();
void client_socket(QTcpSocket* c_socket);
protected:
void closeEvent(QCloseEvent *);
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
void tcp_recv();
void on_pushButton_3_clicked();
signals:
void cbox_close();
private:
Ui::chat_box *ui;
QTcpSocket *socket;
};
#endif // CHAT_BOX_H
----------------------------------login.h----------------------------------
//# pragma execution_character_set("utf-8")
#ifndef LOGIN_H
#define LOGIN_H
#include
#include
#include
#include
#include
#include
#include
#include "chat_box.h"
namespace Ui {
class login;
}
class login : public QWidget
{
Q_OBJECT
public:
explicit login(QWidget *parent = 0);
~login();
QTcpSocket* c_socket();
protected:
void closeEvent(QCloseEvent *);
private slots:
void on_pushButton_2_clicked();
void on_pushButton_clicked();
void login_clear();
void Login_verification();
void zc_verification();
void back_login();
// void open_socket();
// void paintEvent(QPaintEvent *event);
void on_pushButton_3_clicked();
void on_pushButton_4_clicked();
private:
Ui::login *ui;
QTcpSocket *socket;
QString name = NULL;
QString passwd = NULL;
};
#endif // LOGIN_H
----------------------------------chat_box.cpp----------------------------------
#include "chat_box.h"
#include "ui_chat_box.h"
chat_box::chat_box(QWidget *parent) :
QWidget(parent),
ui(new Ui::chat_box)
{
ui->setupUi(this);
this->setWindowIcon(QIcon(":/icon/chat.png"));
this->setWindowTitle("WeChat");
this->setFixedSize(592,414);
connect(ui->lineEdit,SIGNAL(returnPressed()),ui->pushButton,SIGNAL(clicked()), Qt::UniqueConnection);
}
void chat_box::closeEvent(QCloseEvent *)
{
//在退出窗口之前,实现希望做的操作
QString data = "####i will off";
socket->write(data.toStdString().c_str());
socket->disconnectFromHost();
}
void chat_box::client_socket(QTcpSocket *c_socket)
{
socket = c_socket;
connect(socket,SIGNAL(readyRead()),this,SLOT(tcp_recv()));
}
void chat_box::tcp_recv()
{
char buf[40960] = {0};
memset(buf,0,sizeof(buf));
QString data;
socket->read(buf,sizeof(buf));
data = QString(buf);
QString data1 = data;
QString data2 = data;
QString data3 = data;
QString text1 = data1.mid(0,20);
QString text2 = data2.mid(0,22);
QString text3 = data3.mid(0,13);
if(text1 == "###Timeout detection")
{
socket->disconnectFromHost();
this->close();
}
else if(text2 == "###super administrator")
{
QString server_data = "server:";
QString server = data.replace("###super administrator","");
server_data.append(server);
ui->textEdit->append(server_data);
}
else if(text3 == "###online_num")
{
ui->textEdit_2->clear();
QString num = data.replace("###online_num","");
QString count = "当前在线人数:";
count.append(num);
ui->textEdit_2->insertPlainText(count);
ui->textEdit_2->setAlignment(Qt::AlignCenter);
}
else
{
ui->textEdit->append(data);
}
}
void chat_box::on_pushButton_2_clicked()
{
//返回login界面
emit cbox_close();
this->close();
}
void chat_box::on_pushButton_clicked()
{
//发送
QString data = ui->lineEdit->text();
ui->textEdit->setReadOnly(true);
ui->textEdit->append(data);
socket->write(data.toStdString().c_str());
ui->lineEdit->clear();
}
chat_box::~chat_box()
{
delete ui;
}
void chat_box::on_pushButton_3_clicked()
{
//关闭
QString data = "###i will off";
socket->write(data.toStdString().c_str());
}
----------------------------------login.cpp----------------------------------
#include "login.h"
#include "ui_login.h"
login::login(QWidget *parent) :
QWidget(parent),
ui(new Ui::login)
{
ui->setupUi(this);
this->setWindowTitle("Login");
this->setWindowIcon(QIcon(":/icon/login.png"));
this->setFixedSize(414,302);
ui->pushButton_2->setFocus();
ui->pushButton_2->setShortcut(QKeySequence::InsertParagraphSeparator);
ui->pushButton_2->setShortcut(Qt::Key_Enter); //小键盘Enter
ui->pushButton_2->setShortcut(Qt::Key_Return); //大键盘Enter
socket = new QTcpSocket(this);
// socket->connectToHost("***.***.***.***",***); //连接 你的服务器ip和端口 eg:192.168.56.15 8888
}
login::~login()
{
delete ui;
}
QTcpSocket* login::c_socket()
{
QTcpSocket *c_socket = socket;
return c_socket;
}
void login::on_pushButton_2_clicked()
{
//登陆
QString name = ui->lineEdit->text();
QString passwd = ui->lineEdit_2->text(); //获取用户名和密码
QString status = "0";
if(NULL == name)
{
QMessageBox::critical(this,"警告","用户名为空",QMessageBox::No,QMessageBox::No);
return;
}
if(NULL == passwd)
{
QMessageBox::critical(this,"警告","密码为空",QMessageBox::No,QMessageBox::No);
return;
}
/*******发送给服务器*******/
QString sql;
sql.append(name);
sql.append("4tGkOMIzweAbPxrF");
sql.append(passwd);
sql.append("4tGkOMIzweAbPxrF");
sql.append(status);
socket->write(sql.toStdString().c_str());
connect(socket,SIGNAL(readyRead()),this,SLOT(Login_verification()));
}
void login::Login_verification()
{
char buf[16] = {0};
socket->read(buf,sizeof(buf));
QString data = QString(buf);
QString data1 = data.mid(0,16);
if(data1 == "###login success")
{
/*******如果服务器返回true,则登陆成功启动聊天框*******/
chat_box *cbox = new chat_box;
cbox->show();
QString update = "###update";
socket->write(update.toStdString().c_str());
cbox->client_socket(this->c_socket());
connect(cbox,SIGNAL(cbox_close()),this,SLOT(show())); //chat窗口关闭返回login
connect(cbox,SIGNAL(cbox_close()),this,SLOT(login_clear()));
connect(cbox,SIGNAL(cbox_close()),this,SLOT(back_login()));
this->hide(); //隐藏login
}
else if(data1 == "###login false")
{
QMessageBox::about(this," ","登陆失败");
}
disconnect(socket,SIGNAL(readyRead()),this,SLOT(Login_verification()));
}
void login::on_pushButton_clicked()
{
//注册
name = ui->lineEdit->text();
passwd = ui->lineEdit_2->text(); //获取用户名和密码
if(NULL == name)
{
QMessageBox::critical(this,"警告","用户名为空",QMessageBox::No,QMessageBox::No);
return;
}
if(NULL == passwd)
{
QMessageBox::critical(this,"警告","密码为空",QMessageBox::No,QMessageBox::No);
return;
}
/*******发送给服务器*******/
QString data;
data.append(name);
data.append("4tGkOMIzweAbPxrF");
data.append(passwd);
QByteArray ba;
ba.append(data);
const char *c = ba.data();
socket->write(c);
connect(socket,SIGNAL(readyRead()),this,SLOT(zc_verification()));
}
void login::zc_verification()
{
/*******判断注册成功与否*******/
//接收返回值
char buf[24] = {0};
socket->read(buf,sizeof(buf));
QString data = QString(buf);
QString data1 = data.mid(0,24);
if(data1 == "###registration success")
{
/*******注册成功提示*******/
QMessageBox::about(this,"注册消息","成功注册");
}
else if(data1 == "###registration false")
{
/*******注册失败提示*******/
QMessageBox::about(this,"提示","该用户已被注册");
}
disconnect(socket,SIGNAL(readyRead()),this,SLOT(zc_verification()));
}
void login::closeEvent(QCloseEvent *)
{
socket->disconnectFromHost();
}
void login::back_login()
{
//在返回login窗口之前,实现希望做的操作
QString data1 = "#####i will off";
socket->write(data1.toStdString().c_str());
}
void login::login_clear()
{
ui->lineEdit->clear();
ui->lineEdit_2->clear();
}
void login::on_pushButton_3_clicked()
{
//开
char buf[] = "led_on";
socket->write(buf);
}
void login::on_pushButton_4_clicked()
{
//关
char buf[] = "led_off";
socket->write(buf);
}
使用Qlist容器实现多用户套接字存储,数据库提供给注册、登陆查询功能,通过online表显示当前实时在线人数,外观方面还有很大的改进,实在太丑了,欢迎各位大佬在下方留言
V:18875508478 Q:1144535569