QT-Socket编程之模拟TCP五层协议解/封装

3 篇文章 0 订阅

一、消息封/解装仿真系统的设计


1. 结构示意图

按照TCP五层模型仿真消息在两台主机间的通信过程(见下图):

这里写图片描述

2. 基本要求

(1)在发送端模拟数据从高层到低层的封装过程,在接收端模拟数据从低层到高层的解封装过程;
(2)按照每层的功能对数据填加报头,并显示每一层得到的封/解装格式;
(3)传输层和网络层的封装格式参考TCP/IP的相应各层协议格式;
(4)网络层的IP报文需要模拟报文分段和重组的过程;
(5)数据链路层帧格式参考局域网的MAC帧格式;
(6)物理层显示为0或1比


二、具体设计和相关代码

1. 准备

要在QT里面进行Socket编程,必须在QT创建的项目文件开始添加:

QT += core gui network

2. 客户端

(1)先在client.h头文件中引入 #include <QtNetwork>,创建客户端通信套接字

QTcpSocket *c_socket; //客户端通信套接字

(2) 在client.cpp文件中实现:

void client::on_Connect_clicked()
{
    QString ip = ui->IP->text();
    qint16 port = ui->Port->text().toInt();
    if(ip.isEmpty() == true || port == 0)
    {
        QMessageBox::warning(this, "警告", "IP或端口不能为空");
        return;
    }
    c_socket->abort();//断开所有连接
    c_socket->connectToHost(QHostAddress(ip),port);//127.0.0.1"代表主机
    bool connected = c_socket->waitForConnected();
    if(connected){

        OkConnection();
    }
}

//点击发送按钮
void client::on_Send_clicked()
{
    QString message = ui->message->text();//获取发送框内数据
    if(message != "")
    {
        QString buf = message;
        c_socket->write(buf.toUtf8().data());//发送到服务器
    }
    else
    {
        QMessageBox::warning(this, "发送", "发送数据为空!");
        return;
    }
}

(3)客户端UI效果图
这里写图片描述

3. 服务端

(1)先在server.h头文件中引入 #include <QtNetwork>,创建客户端通信套接字

QTcpServer *s_listen;//服务器监听套接字
QTcpSocket *s_socket;//服务器通信套接字

(2)在server.cpp文件中实现:

newListen();
connect(s_listen, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
}

//接受读取消息
void server::revdata()
{
   QString datas = s_socket->readAll();
}

//监听
void server::newListen()

{
     //监听是否有客户端来访,且对任何来访者监听,端口为11111
   if(!s_listen->listen(QHostAddress::Any,SERVER_PORT))
   {
           QMessageBox::warning(this, "监听", "监听失败!");
           return;
   }
}

//接受连接
void server::acceptConnection()
{
    QMessageBox::information(this, "连接状态", "连接成功!");
    ui->send->setEnabled(true);
    s_socket = s_listen->nextPendingConnection();
    connect(s_socket, SIGNAL(readyRead()), this, SLOT(revdata()));
}

(3) 服务端UI效果图
这里写图片描述

4. 封装

PS:详细协议内容参考《计算机网络》(第五版)(谢希仁编著书籍)

commondata.cpp

#include "commondata.h"
#define BUF_SIZE 16
QString AppLayer(QString msg)
{

    QString tmp;
    QString header = "AppHeader";//TCP头
    tmp = header + '#' + msg;
    return tmp;
}


QString TransLayer(QString msg)
{

    QString tmp;
    QString TCPheader;

    //0-15bit Source Port
    QString SourcePort = "0000000011111111";
    //16-31bit Destination Port 11111
    QString DesPort = "0010101101100111";
    //32bits Sequence Number
    QString SequenceNum = "00000000000000000000000000001011";
    //32bits Acknowledgement Number
    QString AckNum = "00000000000000000000000011111011";
    //4bits Header Length
    QString HeaderLength = "0101";
    //6bits Reserved
    QString Reserved ="000000";
    //URG;ACK;PSH;RST;SYN;FIN
    QString Flag = "000000";
    //16bits Window Size
    QString Windowsize = "0000000000000111";
    //16bits Checksum
    QString CheckSum = "0101010101010010";
    //16bits UrgentPointer
    QString UrgentP = "0000000000001111";
    TCPheader = SourcePort + DesPort + SequenceNum + AckNum + \
    HeaderLength + Reserved + Flag + Windowsize + CheckSum + UrgentP;
    tmp = TCPheader + "#" + msg;
    return tmp;
}

QString NetLayer(QString msg)
{
    QString tmp;
    QString NetHeader;

    QString VER = "0100"; //4bits
    QString HLEN = "1111";//4bits
    QString Service = "00000000";//8bits
    QString totalLenth = "0101010101010101";//16bits
    QString Identification = "0000000000000000";//16bits
    QString Flag = "000";//3bits
    QString FragmentationOffset = "0000000000000";//13bits
    QString TTL = "00000000"; //8bits,time to live
    QString Protocol = "00000000";//8bits
    QString HeaderChecksum = "0000000000000000";//16bits
    QString SourIPAddress = "00000000000000000000000000000000";//32bits
    QString DestinationIPAddress = "00000000000000000000000000000000";//32bits
    QString Option = "";
    NetHeader = VER + HLEN + totalLenth + Identification +\
    Flag + FragmentationOffset + TTL + Protocol + HeaderChecksum + SourIPAddress + DestinationIPAddress + Option;
    tmp = NetHeader + '#' + msg;
    return tmp;

}

QString LinkLayer(QString msg)
{
    QString tmp;
    QString FrameFlag1 = "00001111"; // 8bits
    QString FrameAdd = "11101011";//8bits
    QString FrameControl = "01111000";//8bits
    QString FrameData = msg ;
    QString FrameFCS = "1010010101011000";//16bits
    QString FrameFlag2 = "10110101";//8bits
    tmp = FrameFlag1 + FrameAdd + FrameControl + '#' + FrameData + '#' + FrameFCS + FrameFlag2;
    return tmp;

}

QString PhyLayer(QString msg)
{
    QString tmp;
    QString Phyheader = "PhyHeader";//


    tmp = Phyheader + '#' + msg;
    return tmp;

}



三、运行效果

这里写图片描述
这里写图片描述

Qt中实现TCP/IP协议以发送Modbus协议,通常涉及以下几个步骤: 1. 创建一个Qt项目并包含网络模块:首先,确保你的Qt项目文件(.pro)中包含了网络模块的引用,即在文件中添加`QT += network`。 2. 使用QTcpSocket类来实现TCP客户端或服务器:根据你的需求,你可能需要实现一个Modbus TCP客户端或服务器。`QTcpSocket`类允许你连接到TCP服务器,并且能够发送和接收数据。 3. 实现Modbus协议的数据封装析:Modbus协议有几种变体,例如Modbus RTU和Modbus TCP。对于TCP/IP网络,你通常会使用Modbus TCP。你需要根据Modbus协议规范来构建你的请求或响应消息,并且能够析从对端接收到的消息。 4. 连接到Modbus服务器:如果你正在编写客户端代码,你需要连接到运行Modbus服务器的设备。使用`QTcpSocket`的`connectToHost`方法来建立连接。 5. 发送和接收数据:通过`QTcpSocket`对象的`write`方法发送数据,通过`read`或`readAll`方法接收数据。 6. 关闭连接:数据交换完成后,确保通过`QTcpSocket`的`disconnectFromHost`方法断开连接,并且清理资源。 下面是一个简单的示例代码框架,展示了如何使用`QTcpSocket`发送Modbus TCP请求: ```cpp #include <QTcpSocket> #include <QByteArray> #include <QDebug> QTcpSocket *socket = new QTcpSocket(this); connect(socket, &QTcpSocket::connected, this, &YourClass::onConnected); connect(socket, &QTcpSocket::readyRead, this, &YourClass::onReadyRead); connect(socket, &QTcpSocket::disconnected, this, &YourClass::onDisconnected); void YourClass::connectToModbusServer() { socket->connectToHost("192.168.1.100", 502); // Modbus端口号通常是502 } void YourClass::onConnected() { qDebug() << "Connected to Modbus server"; QByteArray data = ...; // 构建Modbus TCP请求数据 socket->write(data); } void YourClass::onReadyRead() { QByteArray data = socket->readAll(); // 处理从Modbus服务器接收到的数据 } void YourClass::onDisconnected() { qDebug() << "Disconnected from Modbus server"; } ``` 在上述代码中,请将`"192.168.1.100"`替换为你的Modbus服务器IP地址,`502`替换为正确的Modbus端口号,并且正确填充`data`变量以构建符合Modbus TCP协议的请求数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值