网盘项目 - 通信协议设计

通信协议设计

一:弹性结构体

可以根据数据大小,灵活申请空间

原理:结构体最后一个成员为 int data [ ]    空的 int类型的数组

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

typedef struct PDU
{
    int a;
    int b;
    int c;
    int d[];  //妙用 写成指针的形式
}PDU;

int main(int argc, char *argv[])
{
    printf("%ld\n", sizeof(PDU));

    PDU *pdu = (PDU*)malloc(sizeof(PDU)+100*sizeof(int)); //空间大小灵活申请
    pdu->a = 90;
    pdu->b = 89;
    pdu->c = 88;
    memcpy(pdu->d, "you jump i jump", 16);

    printf("a=%d,b=%d,c=%d,%s\n", pdu->a, pdu->b, pdu->c, (char*)(pdu->d));


    printf("Hello World!\n");
    return 0;
}

二:通讯协议设计

/* protocol.h */
#ifndef PROTOCOL_H
#define PROTOCOL_H

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

typedef unsigned int uint; //无符号整型

struct PDU    //协议
{
    uint uiPDULen;      //总的协议数据单元大小
    uint uiMsgType;     //消息类型
    char caData[64];
    uint uiMsgLen;      //实际消息长度
    int caMsg[];        //实际消息   通过空的数组地址,访问动态申请的空间
};

PDU *mkPDU(uint uiMssgLen); //创建一个协议数据单元

#endif // PROTOCOL_H
/* protocol.cpp */
#include "protocol.h"

PDU *mkPDU(uint uiMsgLen) //创建一个协议数据单元
{
    uint 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;
}

三:数据收发测试

 客户端

点击 "发送" 按钮,借助槽函数

/* tcpclient.h */
#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#include <QWidget>
#include <QFile>  //操作文件 所用到的 头文件
#include <QTcpSocket>
#include "protocol.h" //包含协议

namespace Ui {
class TcpClient;
}

class TcpClient : public QWidget
{
    Q_OBJECT

public:
    explicit TcpClient(QWidget *parent = 0);
    ~TcpClient();

    // 加载配置文件
    void loadConfig();  //*** Alt + Enter  选第一个 添加函数定义 ***

public slots: //添加槽函数(信号的处理函数)
    void showConnect(); //成功连接服务器会发出connected信号 以此判断是否连接成功


private slots:
    void on_send_pb_clicked();

private:
    Ui::TcpClient *ui;

    QString m_strIp;  //字符型 存放IP
    quint16 m_usPort; //无符号短整型 存放端口号

    QTcpSocket m_tcpSocket; //连接服务器,与其进行数据交互
};

#endif // TCPCLIENT_H
/* tcpclient.cpp */
#include "tcpclient.h"
#include "ui_tcpclient.h"
#include <QByteArray>
#include <QDebug>
#include <QMessageBox>  //用来显示信息
#include <QHostAddress>

TcpClient::TcpClient(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TcpClient)
{
    ui->setupUi(this);

    loadConfig(); //加载配置文件
    connect(&m_tcpSocket, SIGNAL(connected()), this, SLOT(showConnect()));//将信号 与其处理函数 关联起来
    m_tcpSocket.connectToHost(QHostAddress(m_strIp),m_usPort); //连接服务器
}

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

void TcpClient::loadConfig() //加载配置文件
{
    QFile file(":/client.config");
    if(file.open(QIODevice::ReadOnly))//按住ctrl 再点击open 可阅读源码   加上作用域QIODevice
    {
        QByteArray baData = file.readAll(); //字节类型
        QString strData = baData.toStdString().c_str(); //转换为 字符串 char*

        //qDebug() << strData; //"127.0.0.1\r\n8888\r\n"
        file.close();

        strData.replace("\r\n", " "); //将\r\n替换为空格 解析出IP端口
        //qDebug() << strData;

        QStringList strList = strData.split(" "); //按照空格切分
//        for(int i=0; i<strList.size(); i++)
//        {
//            qDebug() << "--->" << strList[i];
//        }

        //转换IP和端口  ip: "127.0.0.1"  port: 8888
        m_strIp = strList.at(0);
        m_usPort = strList.at(1).toUShort();
        //qDebug() << "ip:"<< m_strIp <<" port:" << m_usPort;
    }
    else
    {
        QMessageBox::critical(this, "open config", "open config failed");
    }

}

void TcpClient::showConnect()
{
    QMessageBox::information(this, "连接服务器", "连接服务器成功");
}

/* ***********************本文代码 此处开始******************************  */
void TcpClient::on_send_pb_clicked()  //客户端 发送数据
{
    QString strMsg = ui->lineEdit->text(); //获取输入框信息
    if (!strMsg.isEmpty()) //非空
    {
        PDU *pdu = mkPDU(strMsg.size()+1); //申请数据空间
        pdu->uiMsgType = 8888;     //假定数据类型为 8888
        
        //将要发送的数据copy到 pdu->caMsg
        memcpy(pdu->caMsg, strMsg.toStdString().c_str(), strMsg.size());
        qDebug() << (char*)(pdu->caMsg);

        m_tcpSocket.write((char*)pdu, pdu->uiPDULen); //tcpsocket发送数据
        free(pdu);
        pdu = NULL;
    }
    else //空
    {
        QMessageBox::warning(this, "信息发送", "发送的信息不能为空");
    }
}

服务器 

 将服务器 与 客户端 关联:

        服务器接收客户端连接时,会自动到  incomingConnection (qintptr socketDescriptor)自动生成tcpsocket,并将描述符返回。我们产生一个socket,将描述符保存,就可进行收发数据了

void MyTcpServer::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << "new client connected" ;
    MyTcpSocket *pTcpSocket = new MyTcpSocket; //产生一个socket
    pTcpSocket->setSocketDescriptor(socketDescriptor); //将描述符保存
    m_tcpSocketList.append(pTcpSocket); //放进链表
}

自己封装mytcpsocket

/* mytcpsocket.h */
#ifndef MYTCPSOCKET_H
#define MYTCPSOCKET_H

#include <QTcpSocket> //
#include "protocol.h"

class MyTcpSocket : public QTcpSocket
{
    Q_OBJECT //添加 继承基类 以支持信号槽
public:
    MyTcpSocket();

public slots:  //自己定义槽函数
    void recvMsg();
};

#endif // MYTCPSOCKET_H
/* mytcpsocket.cpp */
#include "mytcpsocket.h"
#include <QDebug>

MyTcpSocket::MyTcpSocket() //自己封装 以方便判断 多个客户端连接产生的多个socket
{
    //本身发出的信号 由本身的槽函数接收
    //实现 各自socket产生的数据 各自处理
    connect(this, SIGNAL(readyRead()), this, SLOT(recvMsg()));
}

void MyTcpSocket::recvMsg() //当MyTcpSocket有数据过来,进行接收
{
    //打印当前发送的数据有多少 数据可能会混乱
    //因此tcpserver也要按照 自定义协议进行接收
    qDebug() << this->bytesAvailable();
    uint uiPDULen = 0;
    this->read((char*)&uiPDULen, sizeof(uint)); //先收4个字节 信息总的大小
    uint uiMsgLen = uiPDULen-sizeof(PDU); //计算实际的消息长度

    PDU *pdu = mkPDU(uiMsgLen);
    this->read((char*)pdu+sizeof(uint), uiPDULen-sizeof(uint)); //偏移位置 接收剩余的数据
    qDebug() << pdu->uiMsgType << (char*)(pdu->caMsg);
}

 服务器程序

/* mytcpserver.h */
#ifndef MYTCPSERVER_H
#define MYTCPSERVER_H

#include <QTcpServer>
#include <QList>
#include "mytcpsocket.h"

class MyTcpServer : public QTcpServer
{   //支持信号槽 条件1:QTcpServer继承基类QObject MyTcpServer又继承了QTcpServer

    Q_OBJECT //支持信号槽 条件2:写上 宏Q_OBJECT
public:
    MyTcpServer();

    static MyTcpServer &getInstance(); //单例模式

    void incomingConnection(qintptr socketDescriptor);

private:
    QList<MyTcpSocket*> m_tcpSocketList; //定义链表 保存所有的socket

};

#endif // MYTCPSERVER_H
/* mytcpserver.cpp */
#include "mytcpserver.h"
#include <QDebug>

MyTcpServer::MyTcpServer()
{

}

MyTcpServer &MyTcpServer::getInstance()
{
    static MyTcpServer instance;
    return instance;
}

void MyTcpServer::incomingConnection(qintptr socketDescriptor)
{
    qDebug() << "new client connected" ;
    MyTcpSocket *pTcpSocket = new MyTcpSocket;
    pTcpSocket->setSocketDescriptor(socketDescriptor);

    m_tcpSocketList.append(pTcpSocket); //放进链表
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: IEEE 1394(又称FireWire或i.Link)是一种高速串行总线协议和接口设计。它由国际电气电子工程师协会(IEEE)制定,用于在电子设备之间传输数据。该协议支持高速数据传输,传输速率可达到400或800 Mbps。 IEEE 1394协议和接口设计的目的是提供一种可靠和快速的数据传输方式,以满足现代电子设备对高带宽和低延迟的需求。它被广泛应用于数字音视频设备、计算机外设和媒体存储设备等领域。 IEEE 1394接口设计包含两个主要组件:主机控制器和设备。主机控制器负责管理和控制数据传输,而设备端连接到主机控制器并提供数据输入/输出功能。接口使用了一种基于流式传输的通信模型,允许设备之间实时传输数据。 IEEE 1394协议定义了数据传输的各种特性和功能。它包括数据包格式、错误检测和纠正机制、时钟同步和电源管理等方面的规定。这些规定确保了数据传输的可靠性和完整性,同时最大限度地提高了传输效率。 如果您想下载IEEE 1394协议及接口设计的PDF文件,您可以在络上搜索相关资源。这些资源通常包括关于协议规范和接口设计的详细文档和说明。通过阅读这些文档,您将能够更深入地了解IEEE 1394的工作原理和应用领域,并可以为您的工程项目或学术研究提供有用的参考资料。 ### 回答2: IEEE 1394协议,也称为FireWire或i.LINK,是一种用于高速数据传输和音视频互联的串行总线协议。它最初由苹果公司在1995年研发,并由IEEE组织在1995年正式发布。 IEEE 1394协议设计初衷是为了满足多媒体数据传输的需求,具有高带宽、低延迟、热插拔以及支持即插即用等特点。该协议可以在计算机、外部设备和消费电子产品之间实现快速的数据传输和设备互连。 IEEE 1394接口是一种用于连接计算机和外部设备的物理连接接口。它提供了高速的数据传输通道和电源供电功能。采用1394接口可以方便地将硬盘、摄像机、打印机、音频设备等设备与计算机进行连接,实现数据的快速传输和设备的共享。 关于IEEE 1394协议及接口设计的PDF下载,可以通过搜索引擎或相关论文数据库来获取相关的资料。很多学术机构、科研机构和技术社区都提供了关于这方面的研究成果和技术文档,可以通过下载PDF文件来深入了解IEEE1394协议和接口设计的详细内容。 总之,对于需要了解IEEE 1394协议及接口设计的人来说,通过下载相关的PDF文献可以获得更多关于这方面的知识和资料,以便更好地理解和应用这一技术。 ### 回答3: ieee1394(又称FireWire或i.LINK)是一种高速串行总线协议和接口设计,用于在电子设备之间传输数据。它由IEEE(电子和电气工程师协会)制定,并于1995年发布。ieee1394通过使用差分信号传输数据,可以实现高带宽(最高可达800Mbps)和实时通信。 ieee1394协议和接口设计的目标是提供一个可靠且快速的数据传输解决方案。它适用于多种应用,如个人电脑、消费电子、音频/视频设备、工业设备等。采用ieee1394接口的设备可以通过简单的连接方式进行互联,实现数据的快速传输和共享。 ieee1394协议和接口设计具有以下特点: 1. 高速传输:ieee1394接口支持高达800Mbps的传输速率,可以满足数据大容量传输和实时应用的需求。 2. 热插拔功能:ieee1394接口支持热插拔功能,即可以在设备工作状态下连接和断开,而无需重新启动设备或计算机。 3. 灵活性:ieee1394接口可以实现数据在设备之间的直接传输,而不需要通过计算机。这使得设备之间的通信更加灵活和高效。 4. 传输质量:ieee1394协议具有错误检测和纠正的功能,能够确保数据的可靠传输。 ieee1394协议及接口设计的PDF文件可以通过互联进行下载。搜索引擎上输入"ieee1394协议及接口设计"即可找到相关的下载链接。这些文档提供了关于ieee1394技术的详细说明、规范和示例,对于开发者和工程师来说非常有用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值