代码
widget.cpp
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
cpp
<?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
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
cpp
#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_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
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