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_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
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_OBJECT
public:
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);
});