QT下TCP协议实现数据网络传输

这篇具有很好参考价值的文章主要介绍了QT下TCP协议实现数据网络传输。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

QT开发框架以其跨平台的优势,在全世界IT界如雷贯耳。其封装了功能齐全的各种类,大大的提高了开发者的效率。本篇内容将介绍如何使用QT 6.4.1框架开发服务器和客户端程序,让两端能够首发消息,服务端往客户端发送文件(客户端往服务器发送类似,没有实现)。

1.运行效果

QT下TCP协议实现数据网络传输

 说明:首先运行同时运行客户端和服务端程序,服务绑定端口开启服务,客户端连接服务器。然后服务器和客户端互相打招呼,然后服务器给客户端发送一首唐诗。

2.关键代码:

2.1服务端代码

2.1.1 服务端主函数

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

2.1.2 QTcpServer实现类

头文件和实现:

#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H

#include <QObject>
#include <QTcpServer>

class MyTcpServer : public QTcpServer
{
    Q_OBJECT
public:
    explicit MyTcpServer(QObject *parent = nullptr);
    //该函数是由框架调用
    void incomingConnection(qintptr socketDescriptor);

signals:
    void newClient(qintptr socket);

};

#endif // MYTCPSERVER_H
#include "mytcpserver.h"

MyTcpServer::MyTcpServer(QObject *parent)
    : QTcpServer{parent}
{

}

//该函数是由框架调用
void MyTcpServer::incomingConnection(qintptr socketDescriptor)
{
    emit newClient(socketDescriptor);
}

2.1.3 主窗口类

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "MyTcpServer.h"
#include <QLabel>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void start(QString file);
    void sendMsg(QByteArray msg);

private slots:
    void on_start_clicked();

    void on_selectFile_clicked();

    void on_sendMsg_clicked();

    void on_transferFile_clicked();

private:
    Ui::MainWindow *ui;
    MyTcpServer *m_server;
    QLabel *m_status;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <QMessageBox>
#include <QRandomGenerator>
#include <qDebug>
#include <QFileDialog>
#include <QString>
#include "sendfile.h"

//alt +回车添加自动添加头文件
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->lineEditPort->setText("9521");
    ui->lineFile->setText("C:\\Users\\Administrator\\Desktop\\OKR设定.txt");
    ui->progressBar->setRange(0, 100);
    ui->progressBar->setValue(0);

    //创建服务器socket
    m_server = new MyTcpServer(this);
    connect(m_server, &MyTcpServer::newClient, this, [=](qintptr socket) {
        ui->textEditContent->append("检测到有新的客户端连接");
        //有新连接
        m_status->setPixmap(QPixmap(":/ok.png").scaled(20, 20));
        QThread *subThread = new QThread;
        SendFile* worker = new SendFile(socket);
        worker->moveToThread(subThread);

        //子线程工作是需要主线程给其发信号通知工作,此处用来通知子线程给客户端发送文件
        connect(this, &MainWindow::start, worker, &SendFile::working);

        connect(worker, &SendFile::done, this, [=](){
            ui->textEditContent->append("检测到客户端退出");
            //客户端断开
            m_status->setPixmap(QPixmap(":/error.png").scaled(20, 20));
            qDebug() << "销毁子线程资源";
            subThread->quit(); //通知退出
            subThread->wait(); //等任务做完
            subThread->deleteLater(); //相当于对new的对象进行delete操作
            worker->deleteLater();
        });
        //不能在子线程操作ui对象,读和写都不行,需要子线程通过信号通知ui线程间接操作ui对象
        connect(worker, &SendFile::text, this, [=](QByteArray msg){
            QVector<QColor> colors = {
                Qt::red, Qt::green, Qt::black, Qt::blue,
                Qt::darkRed, Qt::cyan, Qt::magenta
            };
            int index = QRandomGenerator::global()->bounded(colors.size());
            ui->textEditContent->setTextColor(colors.at(index));
            ui->textEditContent->append(msg);
        });
        //显示客户端发来的消息
        connect(worker, &SendFile::showRecvMsg, this, [=](QByteArray msg){
            ui->textEditContent->append("收到消息:" + msg);
        });

        //通知子线程发送一行文本
        connect(this, &MainWindow::sendMsg, worker, &SendFile::sendMsg);

        connect(worker, &SendFile::updateProgressBar, this, [=](int value){
            ui->progressBar->setValue(value);
        });

        subThread->start();
      });

    //处理状态栏,new一个QLabel,可以制定父对象,也可以不指定,因为需要把
    //它设置到状态栏中,设置后其父对象默认就是状态栏,状态栏析构后就会回收QLabel
    //不用delete
    m_status = new QLabel;
    m_status->setPixmap(QPixmap(":/error.png").scaled(20, 20));
    ui->statusbar->addWidget(new QLabel("状态:"));
    ui->statusbar->addWidget(m_status);
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_start_clicked()
{
    unsigned short port = ui->lineEditPort->text().toUShort();
    //绑定端口等待客户端连接,有客户端连接触发信号:[signal] void QTcpServer::newConnection()
    //QT中用于通信的QTcpSocket套接字对象不能跨线程访问
    m_server->listen(QHostAddress::Any, port);
    ui->start->setDisabled(true);
}


void MainWindow::on_selectFile_clicked()
{
    QString file = QFileDialog::getOpenFileName(this);
    if (!file.isEmpty()) {
        ui->lineFile->setText(file);
    }
}


void MainWindow::on_sendMsg_clicked()
{
   QString msg = ui->lineEditMsg->text();//.toUShort();
   emit sendMsg(msg.toUtf8());
   ui->textEditContent->append("发出消息:" + msg);
}

void MainWindow::on_transferFile_clicked()
{
    if (ui->lineFile->text().isEmpty()) {
        QMessageBox::information(this, "提示", "请选择要发送的文件");
        return;
    }
    emit start(ui->lineFile->text());
}

2.1.4 网络处理线程类

#ifndef SENDFILE_H
#define SENDFILE_H

#include <QObject>
#include <QString>
#include <QTcpSocket>
#include <QtEndian>

class SendFile : public QObject
{
    Q_OBJECT
public:
    explicit SendFile(qintptr socket, QObject *parent = nullptr);
    void working(QString file);
    void sendMsg(QByteArray msg);

signals:
    void done();
    void text(QByteArray msg);
    void showRecvMsg(QByteArray msg);
    void updateProgressBar(int value);

private:
    qintptr m_socket;
    QTcpSocket* m_tcpConn;
};

#endif // SENDFILE_H
#include "sendfile.h"
#include <QThread>
#include <QFile>
#include <qDebug>
#include <QTextCodec>

SendFile::SendFile(qintptr socket, QObject *parent)
    : QObject{parent}
{
    //传递过来了用于通信的套接字,就可以和对端通信了
    m_socket = socket;
}

void SendFile::working(QString file) {
    qDebug() << "子线程ID: " << QThread::currentThread();
    //注意:m_tcpConn的创建要在子线程中
    m_tcpConn = new QTcpSocket;
    //用文件描述符初始化m_tcpConn
    m_tcpConn->setSocketDescriptor(m_socket);

    //检测客户端断开
    connect(m_tcpConn, &QTcpSocket::disconnected, this, [=]() {
        m_tcpConn->close();
        m_tcpConn->deleteLater();
        emit done();
        qDebug() << "检测到客户端退出,我的资源也进行了销毁,再见!";
    });

    //检测客户端发来数据
    connect(m_tcpConn, &QTcpSocket::readyRead, this, [=]() {
        //接收数据并把数据发送给主线程进行显示
        QByteArray data = m_tcpConn->readAll();
        emit showRecvMsg(data);
    });

    qDebug() << "传输的文件: " << file;
    QFile opFile(file);
    bool ret = opFile.open(QFile::ReadOnly);
    if (ret) {
        emit updateProgressBar(0);
        //此处打开的是windows下的文件,windows默认是GBK编码,所以此处指定编码GBK
        QTextCodec *codec = QTextCodec::codecForName("GBK");
        qint64 fileSize = opFile.size();
        qint64 sendSize = 0;
        while (!opFile.atEnd()) {
            //自定格式发包,将发送长度转换成大端存储发送到对端
            QByteArray line = opFile.readLine();
            sendSize += line.size();
            QString strUnicode = codec->toUnicode(line);
            QByteArray utf8line = strUnicode.toUtf8();
            //以下代码写成两行比较稳定,如果写成
            //uint32_t len = qToBigEndian(utf8line.size());在某些环境转换长度就为0
            uint32_t orgLen = utf8line.size();
            uint32_t len = qToBigEndian(orgLen);
            QByteArray data((char*)&len, 4);
            data.append(utf8line);
            //发送一行数据给对端
            m_tcpConn->write(data);
            emit text(utf8line);
            emit updateProgressBar(100 * sendSize / fileSize);
            //为了减轻对端压力,休眠一会
            QThread::sleep(1);
        }
    }
    opFile.close();
}

void SendFile::sendMsg(QByteArray msg) {
    //用文件描述符初始化m_tcpConn
    m_tcpConn = new QTcpSocket;
    m_tcpConn->setSocketDescriptor(m_socket);

    //检测客户端断开
    connect(m_tcpConn, &QTcpSocket::disconnected, this, [=]() {
        m_tcpConn->close();
        m_tcpConn->deleteLater();
        emit done();
    });

    //检测客户端发来数据
    connect(m_tcpConn, &QTcpSocket::readyRead, this, [=]() {
        //接收数据并把数据发送给主线程进行显示
        QByteArray data = m_tcpConn->readAll();
        emit showRecvMsg(data);
    });

    //QT默认是UTF8编码,所以输入框是UTF8编码,此处指定编码方式为UTF8
    QTextCodec *codec = QTextCodec::codecForName("UTF8");
    QString strUnicode = codec->toUnicode(msg);
    QByteArray utf8line = strUnicode.toUtf8();
    uint32_t orgLen = utf8line.size();
    uint32_t len = qToBigEndian(orgLen);
    //拼接头:表示长度
    QByteArray data((char*)&len, 4);
    //拼接发送内容
    data.append(utf8line);
    m_tcpConn->write(data);
}

2.1.5 pro工程文件

QT       += core gui network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
greaterThan(QT_MAJOR_VERSION, 5): QT += core5compat
CONFIG += c++17 console

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp \
    mytcpserver.cpp \
    sendfile.cpp

HEADERS += \
    mainwindow.h \
    mytcpserver.h \
    sendfile.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

2.2客户端代码

2.2.1 主函数

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

2.2.2 主窗口类

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void startConnect(QString, unsigned short);
    void disConnect();
    void sendMsg(QByteArray msg);

private slots:
    void on_connServer_clicked();

    void on_sendMsg_clicked();

    void on_disconnServer_clicked();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <QMessageBox>
#include <QRandomGenerator>
#include "recvfile.h"

//多线程中,主线程负责相应ui事件,创建子线程,子线程处理服务端发过来的数据
//QT中通信的套接字是不能跨线程访问的,所以客户端中用于通信的套接字是不能在
//主线程创建的,需要在子线程创建通讯套接字,主线程把ip和端口传输给子线程
//子线程new一个QTcpSocket的对象,然后子线程用这个通讯套接字接受服务端
//发过来的数据
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->IP->setText("127.0.0.1");
    ui->port->setText("9521");
    ui->disconnServer->setDisabled(true);
    //创建子线程
    QThread *subThread = new QThread;
    //重点说明:此处new RecvFile时候不能给其指定父对象
    //否则worker移动到子线程就会不生效,谨记谨记!!!
    RecvFile* worker = new RecvFile;
    worker->moveToThread(subThread);
    connect(this, &MainWindow::startConnect, worker, &RecvFile::connectServer);
    //连接服务端成功
    connect(worker, &RecvFile::connectOk, this, [=]() {
        //QMessageBox::information(this, "提示", "成功连接了服务器");
        ui->content->append("成功连接了服务器");
        ui->disconnServer->setDisabled(false);
        ui->connServer->setDisabled(true);
    });
    connect(worker, &RecvFile::message, this, [=](QByteArray msg) {
        QVector<QColor> colors = {
            Qt::red, Qt::green, Qt::black, Qt::blue,
            Qt::darkRed, Qt::cyan, Qt::magenta
        };
        int index = QRandomGenerator::global()->bounded(colors.size());
        ui->content->setTextColor(colors.at(index));
        ui->content->append("收到消息:" + msg);
    });
    connect(worker, &RecvFile::gameOver, this, [=]() {
        qDebug() << "主线程销毁子线程";
        subThread->quit();
        subThread->wait();
        subThread->deleteLater();
        worker->deleteLater();
    });
    connect(worker, &RecvFile::disconnected, this, [=] {
        ui->content->append("与服务器断开了连接");
        ui->disconnServer->setDisabled(true);
        ui->connServer->setDisabled(false);
    });
    //断开服务器连接
    connect(this, &MainWindow::disConnect, worker, &RecvFile::disConnect);
    //给服务器发消息
    connect(this, &MainWindow::sendMsg, worker, &RecvFile::sendMsg);
    //start之后,线程仍然不能正常工作,仍然需要信号触发
    subThread->start();
    qDebug() << "主线程id:" << QThread::currentThread();
}

MainWindow::~MainWindow()
{
    delete ui;
}


void MainWindow::on_connServer_clicked()
{
    QString ip = ui->IP->text();
    unsigned short port = ui->port->text().toUShort();
    emit startConnect(ip, port);
}

void MainWindow::on_sendMsg_clicked()
{
    QString msg = ui->msg->text();
    emit sendMsg(msg.toUtf8());
    ui->content->append("发出消息:" + msg);
}

void MainWindow::on_disconnServer_clicked()
{
    emit disConnect();
    ui->disconnServer->setDisabled(true);
    ui->connServer->setDisabled(false);
}

2.2.3 处理网络数据的子线程类

#ifndef RECVFILE_H
#define RECVFILE_H

#include <QByteArray>
#include <QObject>
#include <QTcpSocket>

class RecvFile : public QObject
{
    Q_OBJECT
public:
    explicit RecvFile(QObject *parent = nullptr);
    void connectServer(QString ip, unsigned short port);
    void dealData();
    void disConnect();
    void sendMsg(QByteArray msg);

signals:
    void connectOk();
    void message(QByteArray msg);
    void gameOver();
    void disconnected();

private:
    QTcpSocket *m_tcpScoket;
};

#endif // RECVFILE_H
#include "recvfile.h"
#include <QThread>
#include <QtEndian>

RecvFile::RecvFile(QObject *parent)
    : QObject{parent}
{

}

void RecvFile::connectServer(QString ip, unsigned short port) {
    qDebug() << "子线程ID:" << QThread::currentThread();
    m_tcpScoket = new QTcpSocket;
    //该函数是非阻塞函数,所有需要connect来注册回调,告诉我连接ok
    m_tcpScoket->connectToHost(QHostAddress(ip), port);
    connect(m_tcpScoket, &QTcpSocket::connected, this, &RecvFile::connectOk);
    //连接之后怎么怎么知道有数据到来呢,继续connect连接来通知我,槽使用匿名槽函数
    connect(m_tcpScoket, &QTcpSocket::readyRead, this, [=](){
        //QByteArray all = m_tcpScoket->readAll();
        //emit message(all);
        dealData();
        //emit gameOver();
    });
    connect(m_tcpScoket, &QTcpSocket::disconnected, this, &RecvFile::disconnected);
}

void RecvFile::dealData() {
    unsigned int totalBytes = 0;
    unsigned int recvBytes = 0;
    QByteArray block;

    if (0 == m_tcpScoket->bytesAvailable()) {
        qDebug() << "没有数据";
        return;
    }
    if (m_tcpScoket->bytesAvailable() >= sizeof(int)) {
        QByteArray head = m_tcpScoket->read(sizeof(int));
        //网络字节序转小端
        totalBytes = qFromBigEndian(*(int*)head.data());
        qDebug() << "接收数据长度::" << totalBytes;
    }
    else {
        return;
    }
    while (totalBytes -recvBytes > 0 && m_tcpScoket->bytesAvailable()) {
        block.append(m_tcpScoket->read(totalBytes - recvBytes));
        recvBytes = block.size();
    }
    if (totalBytes == recvBytes) {
        emit message(block);
    }
    //如果还有数据继续读取
    if (m_tcpScoket->bytesAvailable() > 0) {
        dealData();
        qDebug() << "递归调用数据接收";
    }
}

void RecvFile::disConnect() {
    //关闭连接,销毁自己
    m_tcpScoket->close();
    //m_tcpScoket->deleteLater();
}

//给服务器发消息
void RecvFile::sendMsg(QByteArray msg) {
    m_tcpScoket->write(msg);
}

3.开发注意事项

(1)不能在子线程直接操作ui对象,而是通过发送信号给主线程间接操作ui对象

(2)QT处理大端和小端字节序的问题,提供了如下两组四个函数:

  组一(工作于小端机器):  qToBigEndian  (小端转大端)  qFromBigEndian (大端转小端)
  组二(工作于大端机器): qToLittleEndian  (大端转小端)  qFromLittleEndian (小端转大端)

其中组一用在小端机器上,组二用在大端机,简单记忆后缀是BigEndian工作在小段机器,后缀是LittleEndian工作在大端机器,工作机器刚好和后缀相反。

(3)QT有父子对象树机制来回收内存,父对象析构时会先析构子对象。

(4)多线程中,主线程负责相应ui事件,创建子线程,子线程处理服务端发过来的数据QT中通信的套接字是不能跨线程访问的,所以客户端中用于通信的套接字是不能在主线程创建的,需要在子线程创建通讯套接字,主线程把ip和端口传输给子线程子线程new一个QTcpSocket的对象,然后子线程用这个通讯套接字接受服务端发过来的数据

最后附上源码下载地址: https://download.csdn.net/download/hsy12342611/87178417文章来源地址https://www.toymoban.com/news/detail-401055.html

到了这里,关于QT下TCP协议实现数据网络传输的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【网络】传输层TCP协议

    目录 一、概述 2.1 运输层的作用引出 2.2 传输控制协议TCP 简介 2.3 TCP最主要的特点 2.4 TCP连接 二、TCP报文段的首部格式 三、TCP的运输连接管理 3.1 TCP的连接建立(三次握手) 3.2 为什么是三次握手? 3.3 为何两次握手不可以呢? 3.4 TCP的连接释放(四次挥手) 3.5 为什么客户端在TIME

    2024年01月23日
    浏览(28)
  • 【网络编程】传输层协议——TCP协议

    TCP报头当中各个字段的含义如下 源/目的端口号 :表示数据是从哪个进程来,到发送到对端主机上的哪个进程。 32位序号/32位确认序号 :分别代表TCP报文当中每个字节数据的编号以及对对方的确认,是TCP保证可靠性的重要字段。 4位TCP报头长度 :表示该TCP报头的长度,以4字

    2024年02月17日
    浏览(44)
  • 【计算机网络】传输层协议 -- TCP协议

    认识可靠性 现在的计算机大多都是基于冯诺依曼体系结构的 虽然这里的输入设备、输出设备、内存、CPU是在同一个机器上的,但是它们彼此间却是相互独立的。如果它们之间要进行通信,那就必须要用“线”连接起来,其中连接内存和外设之间的“线”叫做IO总线,连接CP

    2024年02月14日
    浏览(39)
  • ESP32网络开发实例-TCP服务器数据传输

    本文将详细介绍在Arduino开发环境中,实现一个ESP32 TCP服务器,从而达到与TCP客户端数据交换的目标。 Internet 协议(IP)是 Internet 的地址系统,具有将数据包从源设备传递到目标设备的核心功能。IP 是建立网络连接的主要方式,奠定了 Internet 的基础。IP 不负责数据包排序或错

    2024年02月07日
    浏览(41)
  • 网络传输层协议:UDP和TCP

    端口号(Port)标识了一个主机上进行通信的不同的应用程序; 在TCP/IP协议中, 用 \\\"源IP\\\", \\\"源端口号\\\", \\\"目的IP\\\", \\\"目的端口号\\\", \\\"协议号\\\" 这样一个五元组来标识一个通信(可以通过 netstat -n查看);  0 - 1023: 知名端口号, HTTP, FTP, SSH 比特科技 等这些广为使用的应用层协议, 他们的端口号

    2024年02月15日
    浏览(40)
  • 网络传输层协议详解(TCP/UDP)

    目录 一、TCP协议 1.1、TCP协议段格式  1.2、TCP原理  确认应答机制 超时重传机制 (安全机制) 连接管理机制(安全机制)  滑动窗口  流量控制(安全机制)  拥塞控制  延迟应答(效率机制) 捎带应答(效率机制)  ​编辑面向字节流(粘包问题)  缓冲区  TCP异常情况  二、UDP协议

    2024年02月06日
    浏览(46)
  • 【传输层】网络基础 -- UDP协议 | TCP协议

    端口号(Port)标识了一个主机上进行通信的不同的应用程序 在TCP/IP协议中,用 “源IP”, “源端口号”, “目的IP”, “目的端口号”, “协议号” 这样一个五元组来标识一个通信(可以通过 netstat -n 查看) 0 - 1023:知名端口号,HTTP,FTP,SSH等这些广为使用的应用层协议,他

    2024年02月09日
    浏览(40)
  • 【计算机网络-传输层】TCP 协议

    端到端通信 :提供应用进程间的端到端通信(逻辑通信)。因此传输层又称为端到端协议。 差错检测 :对首部和数据部分进行检测。 两种协议 :面向连接的 TCP、无连接的 UDP。 复用和分用 : 概念 解释 传输层 TCP 复用 发送方的部分应用进程的报文在传输层使用 TCP 协议进

    2023年04月13日
    浏览(37)
  • 【网络协议】聊聊TCP如何做到可靠传输的

    网络是不可靠的,所以在TCP协议中通过各种算法等机制保证数据传输的可靠性。生活中如何保证消息可靠传输的,那么就是采用一发一收的方式,但是这样其实效率并不高,所以通常采用的是累计确认或者累计应答。 TCP为了保证顺序性,每个包都有一个ID,这个是建立连接之

    2024年02月08日
    浏览(30)
  • 网络原理(四):传输层协议 TCP/UDP

    目录 应用层 传输层 udp 协议  端口号 报文长度(udp 长度) 校验和 TCP 协议 确认应答 超时重传 链接管理 滑动窗口 流量控制 拥塞控制 延时应答 捎带应答 总结 我们第一章让我们对网络有了一个初步认识,第二章和第三章我们通过代码感受了网络通信程序。 而本章的 通信原

    2023年04月27日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包