网盘——通讯协议设计

关于同训协议的设计,主要分为三个部分:弹性结构体、通讯协议设计、数据收发测试

目录

1、弹性结构体

1.1、我们创建一个纯C或者纯C++的项目

A、点击文件——新建项目

B、写上名称,我们叫他structTest

C、根据自己的情况选择,我们选择64位的

D、创建项目如下

1.2、定义一个结构体

 A、打印他的大小

B、假如在定义的结构体里面加上int d[],是一个没有大小的整型数组

1.3、进行弹性空间分配

A、我们使用malloc申请一块没有任何类型的数据

B、我们申请的空间并不是这个结构体,但是将这块控件的首地址强制转换成了PDU,来给到PDU的指针 *pdu

C、那么就可以借助pdu指针来访问空间​编辑

D、也即是产生一块空间,并不是产生这样一个结构体,而是借助结构体来访问空间的相应位置,malloc只是申请了一块没有任何类型的空间,可以转换成任意结构体来用(student\teacher...)

E、注意:

F、对指针变量进行赋值

G、int d[ ],需要将将数据拷贝进去

H、将数据打印出来

I、释放空间

2、通讯协议的设计

2.1、使用代码展示通讯协议

A、点击add new新建一个C++的类

 B、写协议

C、协议操作函数,创建一个.cpp文件

D、定义一些函数,存储一个实际消息的长度

E、计算实际长度

 F、在cpp里面定义,协议动态控件申请一下

2.2、收发数据

A、拖入下图的控件进行测试

B、右键发送控件,转到槽

C、首先获得输入框的信息

D、判断是否为空,空的话就没有必要发送了

E、如果不是空,我们可以看到write的数据是char*类型的,然后发送数据必须封装到协议数据单元里面,在发送出去。所以在tcpclient.h文件里面将协议包含进来

F、在.cpp文件里面产生一个PDU,这样就把空间申请了

G、/拷贝数据 先换成C++的字符串,再获得数据的首地址

H、临时给一个消息类型,做测试

I、那么这个时候消息就封装好啦,封装到pdu里面去了。那么我们把他发送出去

J、发送完之后,将空间free掉,释放空间

K、总的代码

2.3、服务器接收数据

A、在TcpServer这里,添加新文件类

B、将头文件包含进来,并加上Q_OBJECT

C、定义一个槽函数

 D、当socket有数据过来了,发出readyread信号,那么我们就用槽函数来进行接收

E、定义槽函数recvMsg(),打印当前可读的数据大小,bytesAvailable();获得数据大小

F、收数据

G、先收4个字节大小的数据

H、根据总的大小,计算实际消息长度

I、根据实际消息长度,产生一个pdu,接收剩余的数据

J、(char*)pdu +sizeof (uint)从这儿开始放,放uiPDULen-sizeof (uint)些数据

K、打印一下

2.3、与客户端连接

A、定义一个链表,再放到链表里面取

 B、产生一个socket,然后把socketDescriptor描述符放在socket里面,就可以进行收发数据

C、再放到链表里面取 

2.4运行测试

A、先将服务器运行起来

B、再运行客户端

C、客户端连接成功

D、给服务器发送一个数据


1、弹性结构体

也就是说将结构体最后一个成员设计为空的,int caData[ ]

一般定义的结构体都是有固定的大小的,但是弹性结构体是没有固定大小的,它的大小是变化的,实际的原理就是借助一个弹性数组来实现的

1.1、我们创建一个纯C或者纯C++的项目

A、点击文件——新建项目

B、写上名称,我们叫他structTest

C、根据自己的情况选择,我们选择64位的

D、创建项目如下

1.2、定义一个结构体

typedef struct PDU
{
    int a;
    int b;
    int c;
}PDU;

 A、打印他的大小

int main()
{
    //将他的数据打印出来
    printf("%ld\n", sizeof (PDU));
    printf("Hello World!\n");
    return 0;
}

它得到的大小就是三个整型的大小,是12(3X4=12) 

B、假如在定义的结构体里面加上int d[],是一个没有大小的整型数组

int d[];

运行得到结果还是12,实际上并没有占据空间,因为我们并没有对他进行分配空间

1.3、进行弹性空间分配

那没有对他分配空间,那我们如何通过它实现弹性空间分配呢?

A、我们使用malloc申请一块没有任何类型的数据

   PDU *pdu = (PDU*) malloc(sizeof (PDU)+100*sizeof(int));

B、我们申请的空间并不是这个结构体,但是将这块控件的首地址强制转换成了PDU,来给到PDU的指针 *pdu

C、那么就可以借助pdu指针来访问空间

D、也即是产生一块空间,并不是产生这样一个结构体,而是借助结构体来访问空间的相应位置,malloc只是申请了一块没有任何类型的空间,可以转换成任意结构体来用(student\teacher...)

E、注意:

也就是说printf("%ld\n", sizeof (PDU));运行这句代码的时候,实际上只是abc的大小,那么在malloc的时候加了abc的大,又加了100个int,也即是说这个空间有103个int大小,那么我们将这块空间的地址转换成PDU类型的,借助PDU里面的数据成员的类型,访问到这块空间的相应位置。

它的弹性就在一后面的100可以修改为任意数字

int main()
{
    printf("%ld\n", sizeof (PDU));
    PDU*pdu = (PDU*) malloc(sizeof (PDU)+100*sizeof(int));
    printf("Hello World!\n");
    return 0;
}

F、对指针变量进行赋值

    pdu->a=90;
    pdu->b =89;
    pdu->c=88;

G、int d[ ],需要将将数据拷贝进去

    //将数据拷贝进去
    memcpy(pdu->d,"you jump i jump", 16) ;

H、将数据打印出来

     //第四个数组是将字符串打印出来
    printf("a=%d ,b=%d, c=%d, %s\n", pdu->a, pdu->b, pdu->c,(char*)(pdu->d));

I、释放空间

   //释放空间
    free(pdu);
    pdu=NULL;

2、通讯协议的设计

关于通讯协议的设计,我们发送的数据,应该包含四个内容:总的消息大小、消息类型、实际消息大小、实际消息

总的数据大小:uiPDULen (protocol data unity协议数据单元),目的就是在发送的时候数据量不一样的时候,接收数据的时候不能像固定大小那样去接收,首先得知道有多少数据过来了,然后我要申请一个多大的空间去接收它。

消息类型:uiMsgType,我收到你的消息过来的时候,那我要知道你这个数据是干什么的,是登陆还是注册等等

实际消息大小:uiMsgLen,也即是除了前面3个字段外(也就是1里面的abc),其他的数据(也即是you jump i jump).,其实也可以不写,因为我们可以根据总的数据大小减去前面三个字节的大小,就得到了实际消息大小。当然我们也可以加上其他的,上传下载文件,加一个caFileName,可以写成一个数组形式caFData[32](登录注册的时候可以用)

实际消息: aMsg[],这里并不是说将实际消息放在这个数组里面,而是动态去访问这个数据

2.1、使用代码展示通讯协议

A、点击add new新建一个C++的类

 B、写协议

#ifndef PROTOCAL_H
#define PROTOCAL_H

typedef  unsigned int unit;
struct PDU{
    unit uiPDULen; //总的协议数据单元大小
    unit uiMsgType; //消息类型,数据是干嘛的
    char caData[64]; //文件名
    unit uiMsgLen; //实际消息长度
    int caMsg[]; //实际消息
};

#endif // PROTOCAL_H

C、协议操作函数,创建一个.cpp文件

D、定义一些函数,存储一个实际消息的长度

PDU *mkPDU(unit uiMsgLen);

E、计算实际长度

首先引入头文件

#include <stdlib.h>
#include <unistd.h>
#include <string.h>

 F、在cpp里面定义,协议动态控件申请一下

PDU *mkPDU(unit uiMsgLen)
{
    /*
    sizeof(PDU)只会计算 以下的大小      
    unit uiPDULen; //总的协议数据单元大小
    unit uiMsgType; //消息类型,数据是干嘛的
    char caData[64]; //文件名
    unit uiMsgLen; //实际消息长度
    */
    //所以总的数据大小就是前面的,加上实际大小
    unit uiPDULen = sizeof(PDU) +uiMsgLen;
    PDU *pdu = (PDU*) malloc(uiPDULen);
    //清空一下
    if(NULL == pdu){
        //结束程序
        exit(EXIT_FAILURE);
    }
    memset(pdu, 0,uiPDULen);
    //重置
    pdu->uiPDULen = uiPDULen;
    pdu->uiMsgLen = uiMsgLen;
    return  pdu;
            
            
}

2.2、收发数据

在客户端做一个简单的测试

A、拖入下图的控件进行测试

B、右键发送控件,转到槽

 

C、首先获得输入框的信息

QString strMsg = ui->lineEdit->text();

D、判断是否为空,空的话就没有必要发送了

if(!strMsg.isEmpty())
{
    
}    
else
{
        QMessageBox::warning(this, "信息发送", "发送的信息不能为空");
}

E、如果不是空,我们可以看到write的数据是char*类型的,然后发送数据必须封装到协议数据单元里面,在发送出去。所以在tcpclient.h文件里面将协议包含进来

//将协议包含进来
#include "protocal.h"

F、在.cpp文件里面产生一个PDU,这样就把空间申请了

strMsg.size()+1加一个\0

PDU *pdu = mkPDU(strMsg.size()+1);

G、/拷贝数据 先换成C++的字符串,再获得数据的首地址

memcpy(pdu->caMsg, strMsg.toStdString().c_str(),strMsg.size());

H、临时给一个消息类型,做测试

 pdu->uiMsgType=8888;

I、那么这个时候消息就封装好啦,封装到pdu里面去了。那么我们把他发送出去

m_tcpSocket.write((char*)pdu, pdu->uiPDULen);

J、发送完之后,将空间free掉,释放空间

//释放空间
free (pdu);
pdu =NULL;

K、总的代码

void TcpClient::on_sendBt_clicked()
{
    //首先获得输入框的信息
    QString strMsg = ui->lineEdit->text();
    if(!strMsg.isEmpty()){
        //直接发送出去
        //协议
        //strMsg.size()+1加一个\0
        PDU *pdu = mkPDU(strMsg.size()+1);
        //消息类型
        pdu->uiMsgType=8888;
        //拷贝数据 先换成C++的字符串,再获得数据的首地址
        memcpy(pdu->caMsg, strMsg.toStdString().c_str(),strMsg.size());
        m_tcpSocket.write((char*)pdu, pdu->uiPDULen);
        //释放空间
        free (pdu);
        pdu =NULL;
    }
    else {
        QMessageBox::warning(this, "信息发送", "发送的信息不能为空");
    }
}

2.3、服务器接收数据

在这里,我们自己封装一个TcpSocket,假如直接new一个TcpSocket的话,保存socketDescriptor描述符的话,到时候发送数据过来的话,就不知道是谁发的

A、在TcpServer这里,添加新文件类

B、将头文件包含进来,并加上Q_OBJECT

#include "protocal.h"

C、定义一个槽函数

private slots:
    //定义槽函数
    void recvMsg();

 D、当socket有数据过来了,发出readyread信号,那么我们就用槽函数来进行接收

MyTcpSocket::MyTcpSocket()
{
    connect(this, SIGNAL(readyRead()), this, SLOT(recvMsg()));
}

E、定义槽函数recvMsg(),打印当前可读的数据大小,bytesAvailable();获得数据大小

 qDebug()<<this->bytesAvailable();

但是这个容易发生混乱,比如有两个数据一起过来了,直接读两个数据没有分开读的话,就会发生数据混乱,所以我们读数据的时候,先读取PDU的大小,申请空间,接着再读取剩余的数据。所以将前面的protocol.h和.cpp文件都放在里面 

F、收数据

uint uiPDULen =0;

G、先收4个字节大小的数据

this->read((char*)&uiPDULen, sizeof (uint));

H、根据总的大小,计算实际消息长度

uint uiMsgLen = uiPDULen-sizeof (PDU);

I、根据实际消息长度,产生一个pdu,接收剩余的数据

PDU *pdu = mkPDU(uiMsgLen);

J、(char*)pdu +sizeof (uint)从这儿开始放,放uiPDULen-sizeof (uint)些数据

this->read((char*)pdu +sizeof (uint),uiPDULen-sizeof (uint));

K、打印一下

qDebug()<<pdu->uiMsgType<<(char*)pdu->caMsg;

2.3、与客户端连接

Tcpserver监听之后,一旦有客户端过来,他就会自动去调用incomingConnection。

A、定义一个链表,再放到链表里面取

在mytcoserver.h里面添加头文件

#include <QList>
#include "mytcpsocket.h"
private:
    QList <MyTcpSocket*> m_tcpSocketList;

 B、产生一个socket,然后把socketDescriptor描述符放在socket里面,就可以进行收发数据

MyTcpSocket *pTcpSocket = new MyTcpSocket;
pTcpSocket->setSocketDescriptor(socketDescriptor);

C、再放到链表里面取 

m_tcpSocketList.append(pTcpSocket);

2.4运行测试

A、先将服务器运行起来

B、再运行客户端

C、客户端连接成功

D、给服务器发送一个数据

接收成功

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
IEEE1394是一种高速串行总线协议,也被称为FireWire或i.LINK。它是由美国电子电气工程师协会(IEEE)制定的一项标准,用于在计算机硬件和外围设备之间进行快速数据传输。 IEEE1394协议提供了一种可靠和高效的通信方式,支持高速数据传输速率和多设备接入。它能够支持数据传输速率高达800 Mbps,并且可以同时连接多达63个设备。其主要特点包括全双工通信、热插拔能力、自动配置和支持高质量音视频传输等。 IEEE1394接口设计pdf网盘是一个用于存储和共享IEEE1394协议相关资料的网络存储空间。通过这个网盘,用户可以方便地下载和浏览与IEEE1394协议和接口设计相关的PDF文档和资料。这些资料包括协议规范、硬件设计指南、驱动程序等,有助于开发人员了解和实现IEEE1394协议在硬件和软件方面的相关设计。 使用IEEE1394协议及接口设计pdf网盘能够帮助开发人员更好地理解和应用IEEE1394协议,从而提高数据传输的效率,并支持各种高性能应用,如音视频编辑、传输和存储等。这种网盘的使用方便且灵活,开发人员可以随时获取最新的资料和信息,以满足不断发展的技术需求。 总之,IEEE1394协议及接口设计pdf网盘是一个方便用户获取与IEEE1394协议相关资料的平台,通过这个平台,用户可以更好地理解和应用IEEE1394协议,实现高速数据传输和各种多媒体应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值