QT中的TCP
QT中的TCP
回显服务器
-
创建界⾯. 包含⼀个 QListWidget , ⽤于显⽰收到的数据.
-
创建 QTcpServer 并初始化
修改 widget.h, 添加 QTcpServer 指针成员.
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QTcpServer>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void processConnection();QString process(const QString request);
private:Ui::Widget *ui;QTcpServer *tcpServer;
};
#endif // WIDGET_H
修改 widget.cpp, 实例化 QTcpServer 并进⾏后续初始化操作.
• 设置窗⼝标题
• 实例化 TCP server. (⽗元素设为当前控件, 会在⽗元素销毁时被⼀起销毁).
• 通过信号槽, 处理客⼾端建⽴的新连接.
• 监听端⼝
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//1.修改窗口标题this->setWindowTitle("服务器");//2.创建TcpServer的实例tcpServer=new QTcpServer(this);//3.通过信号槽,指定如何处理connect(tcpServer,&QTcpServer::newConnection,this,&Widget::processConnection);//4.绑定监听端口号bool ret=tcpServer->listen(QHostAddress::Any,9090);if(!ret){QMessageBox::critical(this,"服务器启动失败",tcpServer->errorString());exit(1);}
}
- 继续修改 widget.cpp, 实现处理连接的具体⽅法 processConnection
• 获取到新的连接对应的 socket.
• 通过信号槽, 处理收到请求的情况
• 通过信号槽, 处理断开连接的情况
Widget::~Widget()
{delete ui;
}void Widget::processConnection()
{QTcpSocket* clientSocket=tcpServer->nextPendingConnection();QString log="["+clientSocket->peerAddress().toString()+":"+QString::number(clientSocket->peerPort())+"]客户端上线";ui->listWidget->addItem(log);connect(clientSocket,&QTcpSocket::readyRead,this,[=](){QString request=clientSocket->readAll();const QString& response=process(request);clientSocket->write(response.toUtf8());QString log = QString("[") + clientSocket->peerAddress().toString()+ ":" + QString::number(clientSocket->peerPort()) + "] 客⼾端下线!";ui->listWidget->addItem(log);clientSocket->deleteLater();});
}
- 实现 process ⽅法, 实现根据请求处理响应.
由于我们此处是实现回显服务器. 所以 process ⽅法中并没有包含实质性的内容.
QString Widget::process(const QString request)
{return request;
}
💡 “根据请求处理响应” 是服务器开发中的最核⼼的步骤.
⼀个商业服务器程序, 这⾥的逻辑可能是⼏万⾏⼏⼗万⾏代码量级的.
此时, 服务器程序编写完毕.
但是直接运⾏还看不出效果. 还需要搭配客⼾端来使⽤
回显客⼾端
- 创建界⾯. 包含⼀个 QLineEdit , QPushButton , QListWidget
• 先使⽤⽔平布局把 QLineEdit 和 QPushButton 放好, 并设置这两个控件的垂直⽅向的sizePolicy 为 Expanding
• 再使⽤垂直布局把 QListWidget 和上⾯的⽔平布局放好.
• 设置垂直布局的 layoutStretch 为 5, 1 (当然这个尺⼨⽐例根据个⼈喜好微调).
- 创建 QTcpSocket 并实例化
修改 widget.h, 创建成员.
class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();private slots:void on_pushButton_clicked();private:Ui::Widget *ui;QTcpSocket*socket;
};
#endif // WIDGET_H
修改 widget.cpp, 对 QTcpSocket 进⾏实例化.
• 设置窗⼝标题
• 实例化 socket 对象 (⽗元素设为当前控件, 会在⽗元素销毁时被⼀起销毁).
• 和服务器建⽴连接.
• 等待并确认连接是否出错
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//1.设置窗口标题this->setWindowTitle("客户端");//2.创建socket对象实例socket=new QTcpSocket(this);//3.和服务器建立连接socket->connectToHost("127.0.0.1",9090);//4.连接信号槽connect(socket,&QTcpSocket::readyRead,this,[=](){//a)读取响应内容QString response=socket->readAll();//b)把相应内容显示到界面上ui->listWidget->addItem("服务器说:"+response);});//5.等待连接的结果,确认是否成功bool ret=socket->waitForConnected();if(!ret){QMessageBox::critical(this,"服务器连接错误",socket->errorString());exit(1);}
}
- 修改 widget.cpp, 给按钮增加点击的 slot 函数, 实现发送请求给服务器
void Widget::on_pushButton_clicked()
{//1.获取到输入框中的内容const QString& text=ui->lineEdit->text();//2.发送数据到服务器socket->write(text.toUtf8());//3.把发的消息显示到界面上ui->listWidget->addItem("客户端说:"+text);//4.清空输入框的内容ui->lineEdit->setText("");
}
- 修改 widget.cpp 中的 Widget 构造函数, 通过信号槽, 处理收到的服务器的响应.
connect(socket,&QTcpSocket::readyRead,this,[=](){//a)读取响应内容QString response=socket->readAll();//b)把相应内容显示到界面上ui->listWidget->addItem("服务器说:"+response);});
的服务器的响应.
connect(socket,&QTcpSocket::readyRead,this,[=](){//a)读取响应内容QString response=socket->readAll();//b)把相应内容显示到界面上ui->listWidget->addItem("服务器说:"+response);});