C/S架构即时聊天程序程序设计——通信协议设计

此次讨论的协议是数据传输时遵照的一定格式。

协议要求

一个好的通信协议,首先要囊括所有需要发送的信息,能适应各种发送情况,不管你需要向服务端发送一条消息,还是需要验证登录,都可以通过固定的协议格式发送。在这个基础上应该尽量精简,减少打包发送和解包读取的工作量,减轻双方的负担。所以在设计协议之前我们需要讨论都有可能发送何种消息,根据具体的需求确定具体的协议。此外在协议基础上应留有一定的扩展空间,在未来有更多需求的时候可以依据此协议进行修改内容。

通信种类分析

在聊天室例子中,只有两种情况,客户端发给服务端还有服务端发给客户端。

  • 客户端发给服务端:
    • 验证登录——登录ID、密码
    • 请求注册——注册ID、密码
    • 发送消息——发送方ID、接受方ID、消息内容
  • 服务端发给客户端
    • 登录验证情况—— 登录ID、成功或失败、失败原因
    • 注册验证情况——注册ID、注册成功或失败、失败原因
    • 转发消息——发送方ID、接收方ID、消息内容

分析完通信种类我们不难得出一下几种结论。

  • 无论是何种类型的消息,都需要包括发送者ID、接收者ID。这指明了这个数据包的来源和去向。
  • 服务端和客户端都需要根据收到包类型的不同,进行不同的处理。我们可以在包中提前设计这样的数据结构,直接告诉对端应该以哪种方式处理这个包。
  • 包中有一段内容不是固定不变的,有些处理中需要这段内容,有的则不需要。

协议设计

根据分析,我们将数据包处理成四段,分别包括:

字段空间说明
type4字节包类型
sender32字节发送者ID
recver32字节接受者ID
message956字节自由空间

type指定包类型,接受者根据类型选择不同的处理方式;sender指明包的来源,recver指定包的接收方。message是一块自由空间,根据包类型设置对应内容或者不设置。
包空间划分
每各字段有固定的空间范围,这样数据包的长度固定,方便发送和接收,避免数据量大时发生黏包问题。
此时约定双方发送的格式,按照如下格式设置各字段内容。

种类typesenderrecvermessage
登录Login登录IDserverpassword
登录验证Loginserver登录IDsuccess/pass error/id error
注册Regis注册IDserverpassword
注册验证Regis注册IDserversuccess/rename id
发送消息Msg发送ID接收ID消息内容
转发消息Msg发送ID接收ID消息内容

收发双方都应该按照如上格式设置协议包的各字段,打包和解包数据。

代码实现

我们可以使用一个结构体保存包的各个字段,方便解包和打包。在网络发送时,send和recv函数发送和接收的都是void *的一块无类型的空间,我们需要将有类型的数据处理成无类型的数据,发送到对端后,再转换成有类型的数据。

// package.c
// 类型
enum type
{
    Login = 0x01,
    Regis,
    Msg
};

// 消息结构体,1024字节大小
typedef struct package
{
    int type;
    char sender[32];
    char recver[32];
    char message[1024 - 68];
} s_package;

typedef s_package *pt_package;

/**
 * pack是打包的结构体
 * return发送的内容
 * */
void *pack_msg(pt_package pack)
{
    return (void *)pack;
}

/**
 * buf是收到的消息
 * 返回解包后的结构体指针
 * */
pt_package get_package(void *buf)
{
    return (pt_package)buf;
}

/**
 * type是包类型
 * send_name是发送者姓名
 * recv_name是接受者姓名
 * msg是发送的消息
 * 返回数据结构体
 * ps.数据超过指定大小后会舍弃
 * */
pt_package pack_package(int type, char *send_name, char *recv_name, char *msg)
{
    pt_package pack = (pt_package)malloc(sizeof(s_package));
    pack->type = type;
    strncpy(pack->sender, send_name, 32);
    strncpy(pack->recver, recv_name, 32);
    strncpy(pack->message, msg, 1024 - 68);
    return pack;
}
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值