一个简单的SOCKET程序的数据包结构和封解包函数

/*练习写套接字通信程序时候写的一段代码,本来想写个聊天室但写来写去进度卡在界面上接节下来都是通信部分的代码
因为只是试验用所以都是用C写的,等界面部分完工后会用类来封装一下
因为本人E文很烂所以变量和函数的命名是具有中国特色的,求理解.不过我注释的很详细了
谨以此文纪念我那坑爹的编程自学生涯......................**/
 
#include "stdio.h"
#include <windows.h>
//数据包接构//
//数据包类型CTOS为客户端使用的数据包,STOC为服务端使用的数据包
#define CTOS 1
#define STOC 2
//数据包存储管道每个包最大为2000字节,其中数据载荷为最大1800字节,其余留着扩展数据包头
struct SJGD {
 BYTE sjgd[2000];  //数据缓冲区
 DWORD sjcd;    //数据长度
};
//数据包头大小为8字节
struct MSG_TOU {
     DWORD lxid; //数据包类型
     DWORD sxid;  //数据包顺序标号 
  DWORD sjbcd; //数据包长度
};
//服务端-》客户端包
struct MSG_STOC {
    DWORD cmd;    //命令标识
 DWORD sjbcd; //整个MSG_STOC数据包缓冲区的长度
 BYTE shuju[1000];   //附加数据缓冲区
};
//客户端-》服务器包
struct MSG_CTOS {
    DWORD cmd;    //命令标识
 DWORD sjbcd; //整个MSG_CTOS数据包缓冲区的长度
 BYTE shuju[1800]; //附加数据缓冲区
};
//共用体
 union MSG_DATA {
      struct MSG_STOC msg_stoc;
   struct MSG_CTOS msg_ctos;
    };
//完整数据包
struct SJB {
 struct MSG_TOU tou; //数据包头
 union MSG_DATA data;  //数据缓冲区
};
/
/
//封包函数第一个参数为数据包类型,第二个为命令标识,这是数据包的重点远控命令会转换成数字在这里传输
//第三个为数据包顺序标号,第四个参数为附加数据缓冲区,第五个参数为打包数据缓冲区
//作用是把数据填充成一个标准的远控数据包为下面的发包做准备
int Fengbao(DWORD lxid,DWORD cmd,DWORD sxid,struct SJGD*sjgd,struct SJB*sjb)
{
 sjb->tou.lxid=lxid;  //填充数据包类型
 sjb->tou.sxid=sxid;  //填充数据包顺序标号
 if(lxid==CTOS)
 {
  sjb->data.msg_ctos.cmd=cmd;  //填充命令标识
  MoveMemory(sjb->data.msg_ctos.shuju,sjgd->sjgd,sjgd->sjcd);  //填充附加数据
  sjb->data.msg_ctos.sjbcd=sjgd->sjcd;  //填充整个附加数据缓冲区的长度
 }
 if(lxid==STOC)
 {
  sjb->data.msg_stoc.cmd=cmd; //填充命令标识
        MoveMemory(sjb->data.msg_stoc.shuju,sjgd->sjgd,sjgd->sjcd);  //填充附加数据
  sjb->data.msg_stoc.sjbcd=sjgd->sjcd;  //填充整个附加数据缓冲区的长度
 }
 sjb->tou.sjbcd=20+sjgd->sjcd;   //填充数据包长度
 if((lxid!=CTOS)&&(lxid!=STOC)) return 0;
 return 1;
}
///
///
//发包函数第一个参数为待发数据包,第二个参数为数据管道缓冲区
//作用是把一个标准数据包以二进制的形式发送到数据管道缓冲区
int Fabao(struct SJB*sjb,struct SJGD*sjgd)
{
 MoveMemory(sjgd->sjgd,&sjb->tou.lxid,4); //填充数据包类型
    MoveMemory(sjgd->sjgd+4,&sjb->tou.sxid,4);//填充数据包顺序标号
 if(sjb->tou.lxid==CTOS)
 {
        MoveMemory(sjgd->sjgd+8,&sjb->tou.sjbcd,4); //填充数据包长度
        MoveMemory(sjgd->sjgd+12,&sjb->data.msg_ctos.cmd,4);//填充命令标识
        MoveMemory(sjgd->sjgd+16,&sjb->data.msg_ctos.sjbcd,4);//填充整个附加数据缓冲区的长度     
        MoveMemory(sjgd->sjgd+20,sjb->data.msg_ctos.shuju,sjb->data.msg_ctos.sjbcd); //填充附加数据
        sjgd->sjcd=sjb->tou.sjbcd; //更新数据管道长度数据
     return 1;
 }
 if(sjb->tou.lxid==STOC)
 {
        MoveMemory(sjgd->sjgd+8,&sjb->tou.sjbcd,4);//填充数据包长度
        MoveMemory(sjgd->sjgd+12,&sjb->data.msg_stoc.cmd,4);//填充命令标识
        MoveMemory(sjgd->sjgd+16,&sjb->data.msg_stoc.sjbcd,4);//填充整个附加数据缓冲区的长度
        MoveMemory(sjgd->sjgd+20,sjb->data.msg_ctos.shuju,sjb->data.msg_stoc.sjbcd); //填充附加数据
        sjgd->sjcd=sjb->tou.sjbcd; //更新数据管道长度数据
     return 1;
 }
 return 0;
}


//函数作用是直接从内存读取一个4字节的整数,为下面的解包做准备
int hex_int(char c)    //从内存读取一个1字节的整数
{
 if((c>='A')&&(c<='F'))
 {
 return (int)(c-'A'+10);
 }
 if((c>='0')&&(c<='9'))
 {
 return (int)(c-'0');
 }
 return 0;
}
DWORD hex_dw(BYTE*hex)   //从内存读取一个4节的整数
{
 DWORD D=0;
    char x[2];
    sprintf(x,"%.2X",hex[0]);
 D+=hex_int(x[1]);
 D+=hex_int(x[0])*16;
    sprintf(x,"%.2X",hex[1]);
 D+=hex_int(x[1])*16*16;
 D+=hex_int(x[0])*16*16*16;
    sprintf(x,"%.2X",hex[2]);
 D+=hex_int(x[1])*16*16*16*16;
 D+=hex_int(x[0])*16*16*16*16*16;
    sprintf(x,"%.2X",hex[3]);
 D+=hex_int(x[1])*16*16*16*16*16*16;
 D+=hex_int(x[0])*16*16*16*16*16*16*16;
 return D;
}
///
///
//解包函数第一个参数是待解包的数据管道缓冲区,第二个参数为解包数据存储结构
//函数作用是把数据管道中的数据解封为一个标准的远控数据包,用以控制程序流程
int Jiebao(struct SJGD*sjgd,struct SJB*sjb)
{
 sjb->tou.lxid=hex_dw(sjgd->sjgd);   //解封数据包类型
 sjb->tou.sxid=hex_dw(sjgd->sjgd+4);  //解封数据包顺序标号
    sjb->tou.sjbcd=hex_dw(sjgd->sjgd+8); //解封数据包长度
 if(sjb->tou.lxid==CTOS)
 {
  sjb->data.msg_ctos.cmd=hex_dw(sjgd->sjgd+12);  //解封命令标识
  sjb->data.msg_ctos.sjbcd=hex_dw(sjgd->sjgd+16); //解封整个附加数据缓冲区的长度
  MoveMemory(sjb->data.msg_ctos.shuju,sjgd->sjgd+20,sjb->data.msg_ctos.sjbcd); //解封附加数据
  return 1;
 }
 if(sjb->tou.lxid==STOC)
 {
        sjb->data.msg_stoc.cmd=hex_dw(sjgd->sjgd+12);  //解封命令标识
  sjb->data.msg_stoc.sjbcd=hex_dw(sjgd->sjgd+16); //解封整个附加数据缓冲区的长度
  MoveMemory(sjb->data.msg_stoc.shuju,sjgd->sjgd+20,sjb->data.msg_ctos.sjbcd); //解封附加数据
  return 1;
 }
 return 0;
}
////

 

转载于:https://www.cnblogs.com/AquaGot/p/7242236.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
和解是在使用Python的socket模块进行数据传输时经常遇到的问题。引用\[1\]中提到了TCP/IP传输中可能出现的粘现象,即多个数据包被接收方当作一个数据包处理。为了解决这个问题,我们需要进行拆和解操作。 在拆过程中,我们需要根据对应的协议进行拆分。例如,如果我们传输的是图像或大文件,可能需要将其拆分成多个数据包进行传输。拆的具体实现可以根据数据的大小和特性进行调整。 解过程中,我们需要根据接收到的数据进行处理。在引用\[2\]中的例子中,使用recv函数接收数据时,我们并不知道即将接收的数据量有多大。因此,我们需要根据具体情况进行解操作。在这个例子中,数据被黏在一起,因为recv函数的最大内存是1024字节,所以我们无法准确知道数据的大小。 在引用\[3\]中的例子中,展示了一个接收图像的例子。在这个例子中,使用select函数来监听连接的客户端socket,然后根据接收到的数据进行拆和解操作。如果接收到的数据以'SIZE'开头,表示接下来的数据是图像的大小信息;如果接收到的数据以'BYE'开头,表示结束连接;否则,将接收到的数据写入文件中。 总结来说,拆和解是在使用Python的socket模块进行数据传输时需要注意的问题。在拆过程中,我们需要根据数据的特性进行拆分;在解过程中,我们需要根据接收到的数据进行处理。这样可以确保数据的正确传输和处理。 #### 引用[.reference_title] - *1* *3* [Python Socket传输图片](https://blog.csdn.net/ACK_ACK/article/details/98144025)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Python网络编程(OSI Socket)](https://blog.csdn.net/MeiJin_/article/details/126180389)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值