服务器端:
头文件
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QList>
#include <QMessageBox>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_startbtn_clicked();void newConnection_slot();void readyRead_slot();private:Ui::Widget *ui;//定义服务器指针QTcpServer *server;//定义客户端容器QList<QTcpSocket *> clientlist;
};
#endif // WIDGET_H
源文件
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//1.实力化一个服务器server = new QTcpServer(this);//此时服务器已经成功进入监听状态,如果客户端向服务器发来连接请求//那么服务器就会自动发射一个newconnection信号,可以在该信号连接到对应的槽函数作出相应处理//3.由于只需要连接一次即可,所以可以将该连接放在构造函数中完成connect(server,&QTcpServer::newConnection,this,&Widget::newConnection_slot);}Widget::~Widget()
{delete ui;
}//启动服务器按钮对应的槽函数
void Widget::on_startbtn_clicked()
{//获取ui界面上的端口号quint16 port = ui->portedit->text().toInt();//2.监听客户端的连接请求if(!server->listen(QHostAddress::Any,port)){QMessageBox::information(this,"失败","监听失败");return ;}else{QMessageBox::information(this,"成功","服务器启动成功");}}//自定义处理newconnection信号的槽函数实现
void Widget::newConnection_slot()
{qDebug()<<"您有新的客户端发来连接请求了";//4.获取最新连接的客户端套接字QTcpSocket *s = server->nextPendingConnection();//将该套接字放入客户端链表中clientlist.push_back(s);//如果客户端发来数据,对应的客户端套接字就会自动发射一个readyRead信号//4.可以将该信号连接到自定义的槽函数中,处理对应的逻辑connect(s,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);
}//readyRead信号对应槽函数的实现
void Widget::readyRead_slot()
{qDebug()<<"有新的客户端消息发来";//遍历客户端链表,将无效的客户端移除for(int i=0;i<clientlist.size();i++){if(clientlist[i]->state()==0){//将该套接字移除客户端容器clientlist.removeAt(i);}}//遍历客户端链表,判断是那个客户端发来的数据for(int i=0;i<clientlist.size();i++){//bytesAvalilable函数,功能:求当前客户端套接字中待读数据的字节数//返回值:字节数,如果是0,表示无数据待读if(clientlist[i]->bytesAvailable()!=0){//将待读的数据读取出来QByteArray msg = clientlist[i]->readAll();//将数据展示到ui界面上ui->msgwidget->addItem(QString::fromLocal8Bit(msg));//将接收到的数据据,转发给所有客户端for(int j=0;j<clientlist.size();j++){clientlist[j]->write(msg);}}}}
ui界面
客户端:
头文件:
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpSocket> //客户端类
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_connectbtn_clicked();//自定义处理conneced信号的槽函数void connected_slot();void readyRead_slot();void on_sendbtn_clicked();void on_disconnectbtn_clicked();void disconnected_slot();
private:Ui::Widget *ui;//定义客户端指针QTcpSocket *socket;//定义字符串接收用户名QString userName;
};
#endif // WIDGET_H
源文件
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//给客户端指针实例化对象socket = new QTcpSocket(this);//此时,已经向服务器发送连接请求了,如果成功连接服务器,那么该客户端就会自动发射一个connected的信号//我们可以将该信号连接到自定义的槽函数中处理逻辑//由于只需要连接一次,所有将连接写在构造函数中connect(socket,&QTcpSocket::connected,this,&Widget::connected_slot);//如果服务器向客户端发来消息,那么客户端就会自动发射一个readyRead信号//我们可以将该进行连接到自定义的槽函数中处理相关逻辑connect(socket,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);//当成功与服务器断开连接后,该客户端会自动发射一个disconned的信号//connect(socket,&QTcpSocket::disconnected,this,&Widget::disconnected_slot);
}Widget::~Widget()
{delete ui;
}//连接服务器按钮定义的槽函数
void Widget::on_connectbtn_clicked()
{//获取ui界面上的相关信息userName =ui->username_edit->text(); //获取用户名QString ip =ui->ip_edit->text(); //主机地址quint16 port =ui->port_edit->text().toUInt(); //端口号//将客户端连接到给定的服务器socket->connectToHost(ip,port);}
//处理conneced信号的槽函数的定义
void Widget::connected_slot()
{QMessageBox::information(this,"成功","您已经成功进入聊天室");//向服务器发送一条数据:***进入聊天室QString msg = userName + "进入聊天室";socket->write(msg.toLocal8Bit()); //将数据写给服务器
}//处理readyRead信号的槽函数的定义
void Widget::readyRead_slot()
{//读取套接字中的信息QByteArray msg = socket->readAll();//将数据展示到ui界面ui->msgWidget->addItem(QString::fromLocal8Bit(msg));
}//发送按钮对应的槽函数
void Widget::on_sendbtn_clicked()
{//获取ui界面输入的内容QString msg = userName+":"+ui->edit1->text();//发送给服务器socket->write(msg.toLocal8Bit());
}
//断开服务器按钮对应的槽函数
void Widget::on_disconnectbtn_clicked()
{//告诉大家我走了QString msg =userName +":离开聊天室";socket->write(msg.toLocal8Bit());//断开连接socket->disconnectFromHost();}//disconnected信号对应槽函数的定义
void Widget::disconnected_slot()
{QMessageBox::information(this,"退出","退出成功");
}
ui界面
效果图