#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer> //服务器文件
#include <QTcpSocket> //客户端头文件
#include <QDebug>
#include <QList> //链表容器
#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_start_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);//实例化一个服务器server = new QTcpServer(this);connect(server,&QTcpServer::newConnection,this,&Widget::newConnection_slot); //绑定newConnection到自定义的newConnection_slot处理函数
}Widget::~Widget()
{delete ui;
}//启动服务器按钮对应的槽函数
void Widget::on_start_clicked()
{quint16 port = ui->port->text().toUInt();//监听客户端的连接请求//函数原型: bool listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0);//参数1:要监听的主机地址,如果是any表示监听任意一个主机地址,也可以是指定的主机地址//参数2:该服务器提供的端口号,如果是0表示有服务器自动指定,一般由程序员指定//返回值:成功进入监听状态,返回true,其他情况返回falseif(!server->listen(QHostAddress::Any,port)){QMessageBox::information(this,"失败","监听失败");return;}else{QMessageBox::information(this,"成功","服务器启动成功");}//此时,服务器进入了监听状态,有客户端向服务器发送连接请求的话,就会自动发射一个newConnection的信号
}//新用户连接信号对应的槽函数
void Widget::newConnection_slot() //说明接收到了一个newConnection
{qDebug()<<"你有新的客户端发来连接请求";//获取最新连接的客户端套接字QTcpSocket *s = server->nextPendingConnection(); //无参数//将该套接字放到客户端链表clientList.push_back(s);//此时,如果客户端向服务器发来数据,那么对应的客户端套接字就会自动发送一个readyRead信号connect(s,&QTcpSocket::readyRead,this,&Widget::readyRead_slot);//将readyRead信号绑定到自定义的槽函数,见下
}//readyRead信号对应的槽函数
void Widget::readyRead_slot() //说明接收到了一个readyRead信号
{qDebug()<<"有客户端发来数据";//遍历客户端链表,将无效的客户端移除for(int i=0;i<clientList.size();i++){//判断当前套接字是否是有效连接,0为无效连接if(clientList[i]->state() == 0) //state用来判断是否有效连接{//将该套接字移除客户端容器clientList.removeAt(i);}}//遍历客户端链表,判断是哪个客户端发来的数据for(int i=0;i<clientList.size();i++){if(clientList[i]->bytesAvailable()!=0){//将该套接字中的数据读取QByteArray msg = clientList[i]->readAll();//将数据展示到ui界面ui->msgWidget->addItem(msg);//将接受的数据,转发给所有客户端for(int j=0;j<clientList.size();j++){clientList[j]->write(msg);}}}}
QT += core gui network/*************************************************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QTcpSocket>
#include <QMessageBox>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_pushButton_clicked();void connected_slot();void readyRead_slot();void on_btn_clicked();void on_pushButton_2_clicked();void disconnected_slot();private:Ui::MainWindow *ui;//定义客户端指针QTcpSocket *socket;//定义字符串接受用户名QString usernem;
};
#endif // MAINWINDOW_H/***************************************************************************/
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//给客户端指针实例化对象socket = new QTcpSocket(this);connect(socket,&QTcpSocket::connected,this,&MainWindow::connected_slot);connect(socket,&QTcpSocket::readyRead,this,&MainWindow::readyRead_slot);connect(socket,&QTcpSocket::disconnected,this,&MainWindow::disconnected_slot);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_pushButton_clicked()
{//获取UI界面上的相关信息usernem = ui->username->text();QString ip = ui->user_ip->text();quint16 port = ui->port->text().toUInt();//将客户端连接到指定的服务器//参数1:服务器的主机地址//参数2:端口号,无返回值socket->connectToHost(ip,port);//此时已经向服务器发送了连接请求,成功连接,客户端就会自动发射一个connected的信号
}void MainWindow::connected_slot()
{QMessageBox::information(this,"成功","连接服务器成功");QString msg = usernem +":进入聊天室";socket->write(msg.toLocal8Bit()); //将数据写给服务器
}void MainWindow::readyRead_slot()
{//读取套接字中的信息QByteArray msg = socket->readAll();//将数据展示到ui界面ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}//发送按钮对应的槽函数
void MainWindow::on_btn_clicked()
{//获取UI界面输入的内容QString msg =usernem + ":" + ui->msg->text();//发送给服务器socket->write(msg.toLocal8Bit());ui->msg->clear();
}//断开按钮对应的槽函数
void MainWindow::on_pushButton_2_clicked()
{//告诉服务器断开连接QString msg = usernem + ":离开聊天室";socket->write(msg.toLocal8Bit());//断开连接socket->disconnectFromHost(); //断开连接的函数//客户端会自动发射一个disconnected的信号
}//disconnected_slot信号对应槽函数的定义
void MainWindow::disconnected_slot()
{QMessageBox::information(this,"提示","退出成功");}