当前位置:网站首页>QT--实现TCP通信
QT--实现TCP通信
2022-06-12 06:14:00 【我有一颗薄荷糖】
提示:本文为学习记录,若有错误,请联系作者,谦虚受教。
前言
生活总是来来往往,千万别等来日方长。
一、TCP协议
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
优点:
(1)基于流的方式;
(2)面向连接;
(3)可靠通信方式;
(4)在网络状况不佳的时候尽量降低系统由于重传带来的带宽开销;
(5)通信连接维护是面向通信的两个端点的,而不考虑中间网段和节点。
详细可见:《TCP网址》
为满足TCP协议的这些特点,TCP协议做了如下的规定:
①数据分片:在发送端对用户数据进行分片,在接收端进行重组,由TCP确定分片的大小并控制分片和重组;
②到达确认:接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认;
③超时重发:发送方在发送分片时启动超时定时器,如果在定时器超时之后没有收到相应的确认,重发分片;
④滑动窗口:TCP连接每一方的接收缓冲空间大小都固定,接收端只允许另一端发送接收端缓冲区所能接纳的数据,TCP在滑动窗口的基础上提供流量控制,防止较快主机致使较慢主机的缓冲区溢出;
⑤失序处理:作为IP数据报来传输的TCP分片到达时可能会失序,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层;
⑥重复处理:作为IP数据报来传输的TCP分片会发生重复,TCP的接收端必须丢弃重复的数据;
⑦数据校验:TCP将保持它首部和数据的检验和,这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到分片的检验和有差错,TCP将丢弃这个分片,并不确认收到此报文段导致对端超时并重发。
《传说中的TCP的三次握手》
上位机作为客户端,主动连接服务器,发送数据,接收数据。
简单理解:
A发送:我要发信息给你啦,你准备好了吗?
B发送:我准备好啦,你发吧!
A发送:好的,那我发送啦。
然后A就开始发送。
这就是理解层面上的三次握手。
以下会有相关QT的简单例子。
二、TCP通信步骤
1.TCP服务端的实现流程
重点:
A. 调用listen监听端口
B. 连接信号newConnection,在槽函数里调用nextPendingConnection获取连接进来的socket。
(1).h引入头文件
#include <QTcpServer>
#include <QTcpSocket>
(2)创建QTcpServer的对象用作监听套接字;
QTcpServer *m_s;
QTcpSocket *m_tcp;
在构造函数中new
//放在构造函数中
m_s = new QTcpServer(this);
(3)使用listen()方法监听网卡的ip和端口
void MainWindow::on_bt_listen_clicked()
{
unsigned short port = ui->lineEdit->text().toUShort();
bool ret =m_s->listen(QHostAddress::Any, port);
if(ret)
{
ui->textEdit->append("启动服务器成功");
}
else {
ui->textEdit->append("error");
}
qDebug()<<ret<<m_s->errorString();
}
(4)发送信息
void MainWindow::on_bt_sendmsg_clicked()
{
QString msg = ui->text_send->toPlainText();
m_tcp->write(msg.toUtf8());
ui->textEdit->append("服务器说:"+msg);
}
(5)关闭连接
void MainWindow::on_bt_close_clicked()
{
//主动和客户端断开连接
if(NULL == m_tcp)
{
return;
}
m_tcp->disconnectFromHost();
m_tcp->close();
m_tcp = NULL;
}
(6)触发上面的槽函数,在构造函数用connect()
当有数据传送的时候,客户端QTcpSocket会触发readyRead()信号,然后readAll()读取数据并显示出来。
connect(m_s,&QTcpServer::newConnection,this,[=]()
{
m_tcp = m_s->nextPendingConnection();
ui->textEdit->append("成功和客户端建立了连接!");
connect(m_tcp,&QTcpSocket::readyRead,this,[=]()
{
QByteArray data = m_tcp->readAll();
ui->textEdit->append("客户端说:"+data);
});
connect(m_tcp,&QTcpSocket::disconnected,this,[=]()
{
ui->textEdit->append("客户端断开了连接!");
m_tcp->close();
m_tcp->deleteLater();
});
});
2.TCP客户端的实现流程
重点:
A. 调用connectToHost连接服务器
B. 调用waitForConnected判断是否连接成功
C. 连接信号readyRead槽函数,异步读取数据
D. 调用waitForReadyRead,阻塞读取数据
E.调用disconnected断开连接
F.调用state() == QAbstractSocket::UnconnectedState和waitForDisconnected判断是否断开连接
(1).h引入头文件
#include <QTcpSocket>
(2)创建QTcpSocket套接字
QTcpSocket *tcpsocket;//通信套接字
构造函数中new
tcpsocket = new QTcpSocket(this);
(3)使用这个对象连接服务器
void MainWindow::on_bt_lianjie_clicked()
{
qint16 port = ui->tcp_com->text().toInt();
//unsigned short ip = ui->ip->text().toUShort();
QString ip = ui->tcp_add->text();
tcpsocket->connectToHost(QHostAddress(ip),port);
if(tcpsocket->waitForConnected(3000))
{
ui->textdisplay->append("连接服务器成功!");
}
else
{
ui->textdisplay->append("连接失败,请检查IP地址和端口!");
}
}
(4)发送信息write()
void MainWindow::on_pushButton_clicked()
{
QString msg = ui->text_send->toPlainText();
ui->textdisplay->append("客户端说:"+msg);
//获取编辑框内容
QString str = ui->text_send->toPlainText();
//发送数据
tcpsocket->write(str.toUtf8().data());
ui->textdisplay->append("客户端发送:"+str);
}
(5)断开连接
void MainWindow::on_bt_duankai_clicked()
{
//主动和对方断开连接
tcpsocket->disconnectFromHost();
tcpsocket->close();
//断开成功
if (tcpsocket->state() == QAbstractSocket::UnconnectedState || tcpsocket->waitForDisconnected(1000))
{
ui->textdisplay->append("连接已断开!");
}
else
{
ui->textdisplay->append("无法断开与服务器的连接!");
}
}
(6)触发上面的槽函数,在构造函数中使用connect()
当客户端的嵌套字socket接收缓冲区有新数据到来时,会发出readRead()信号
connect(tcpsocket,&QTcpSocket::connected,this,[=]()
{
ui->textdisplay->append("成功和服务器建立连接!");
});
connect(tcpsocket,&QTcpSocket::readyRead,this,[=]()
{
QByteArray data = tcpsocket->readAll();
ui->textdisplay->append("服务器说:"+data);
});
connect(tcpsocket,&QTcpSocket::disconnected,this,[=]()
{
//m_tcp->close();
//m_tcp->deleteLater();
ui->textdisplay->append("已和服务器断开连接!");
});

总结
提示:善于总结,多进一步。
边栏推荐
- Unity3d multi platform method for reading text files in streamingasset directory
- Zip and Items() difference
- English语法_副词_有无ly,意义不同
- Using hidden Markov model to mark part of speech
- 夜神模擬器adb查看log
- Cv2.fillpoly coco annotator segment coordinate conversion to mask image
- EBook upload
- 2D human pose estimation for pose estimation - pifpaf:composite fields for human pose estimation
- (UE4 4.27) customize primitivecomponent
- Dlib face detection
猜你喜欢

RNN model

Annotation configuration of filter

C2w model - language model

Word2Vec

IBL of directx11 advanced tutorial PBR (3)

(UE4 4.27) customize globalshader

Getting started with houdininengine HDA and UE4

Cause analysis of motion blur / smear caused by camera shooting moving objects
![How to increase heap size of JVM [duplicate] - how to increase heap size of JVM [duplicate]](/img/65/a214d137e230b1a1190feb03660f2c.jpg)
How to increase heap size of JVM [duplicate] - how to increase heap size of JVM [duplicate]

First note
随机推荐
zip 和.items()区别
Cross compile libev
获取图片的尺寸
PDF. js FAQs
EBook list page
Directx11 advanced tutorial tiled based deffered shading
Unity C script implements AES encryption and decryption
Get the size of the picture
Why is the union index the leftmost matching principle?
Types, functions and applications of intelligent sensors
关于 Sensor flicker/banding现象的解释
SQLite cross compile dynamic library
Leetcode-1604. Warning people who use the same employee card more than or equal to three times within one hour
Why do I object so [1.01 to the power of 365 and 0.99 to the power of 365]
English语法_副词_有无ly,意义不同
Es6-es11 learning
Summary of some problems in sensor bring up
Cv2.fillpoly coco annotator segment coordinate conversion to mask image
Who is more fierce in network acceleration? New king reappeared in CDN field
MySQL master-slave, 6 minutes to master