代码
widget.cpp
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget),p(new QTcpServer(this))//给服务器指针申请空间
{ui->setupUi(this);
}Widget::~Widget()
{delete ui;
}void Widget::on_pushButton_clicked()//启动服务器按钮对应槽函数
{//获取ui界面的端口号quint16 port=ui->lineEdit->text().toUInt();//将获取的行编辑器的字符转为无符号整型//设置服务器监听if(p->listen(QHostAddress::Any,port)){QMessageBox::information(this,"提示","服务器启动成功");}else{QMessageBox::information(this,"提示","服务器启动失败");return;}//此时服务器已建立监听,如客户端发来连接,服务器自动发送一个newConnection()信号//将该信号连接到自定义的槽函数中,处理逻辑connect(p,&QTcpServer::newConnection,this,&Widget::newConnection);
}void Widget::newConnection()//newConnection信号对应槽函数实现
{//获取客户端套接字QTcpSocket *s=p->nextPendingConnection();//将客户端套接字放入容器socketList.push_back(s);//程序运行至此,说明服务器与客户端建立了连接//如果客户端向服务器发来数据,客户端就会自动发送一个readyRead信号(客户端套接字,QtcpScoket),就可以将该信号连接到自定义的槽函数,读取数据connect(s,&QTcpSocket::readyRead,this,&Widget::readyRead);
}void Widget::readyRead()//readyRead信号对应槽函数实现
{//遍历客户端容器,移除无效(断开连接)客户端for(int i=0;i<socketList.count();i++){//获取容器元素个数的函数//判读连接状态,state函数返回值是一个枚举,值为0,表示未连接if(socketList.at(i)->state()==0){socketList.removeAt(i);//删除该元素}}//遍历客户端,判断那个客户端有数据待读for(int i=0;i<socketList.count();i++){//bytesAvailable,数据的字节if(socketList.at(i)->bytesAvailable()!=0){//读取数据QByteArray msg=socketList.at(i)->readAll();//将读取的数据放到ui界面ui->listWidget->addItem(QString::fromLocal8Bit(msg));//fromLocal8Bit字节转为QString//将发送的消息转发给其他客户端for(int i=0;i<socketList.count();i++){socketList.at(i)->write(msg);}}}// p->close();//关闭服务器
}
widget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>Widget</class><widget class="QWidget" name="Widget"><property name="geometry"><rect><x>0</x><y>0</y><width>470</width><height>439</height></rect></property><property name="windowTitle"><string>Widget</string></property><widget class="QListWidget" name="listWidget"><property name="geometry"><rect><x>10</x><y>20</y><width>441</width><height>321</height></rect></property></widget><widget class="QLabel" name="label"><property name="geometry"><rect><x>10</x><y>380</y><width>81</width><height>31</height></rect></property><property name="text"><string>端口号:</string></property></widget><widget class="QLineEdit" name="lineEdit"><property name="geometry"><rect><x>70</x><y>380</y><width>221</width><height>31</height></rect></property></widget><widget class="QPushButton" name="pushButton"><property name="geometry"><rect><x>310</x><y>380</y><width>141</width><height>31</height></rect></property><property name="text"><string>启动服务器</string></property></widget></widget><resources/><connections/>
</ui>
main.cpp
#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>//服务器类
#include <QMessageBox>
#include <QTcpSocket>//套记字类
#include <QList>//链表容器类,是一个类模板
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();
public slots:void newConnection();//newConnection()槽函数void readyRead();//readyRead()信号槽函数private:Ui::Widget *ui;//实例化一个服务器指针QTcpServer *p;//定义存放客户端套接字的容器QList<QTcpSocket *> socketList;
};
#endif // WIDGET_H