标签: 通信协议

应用层常见的几种协议

1)HTTP协议(Hyper Text Transfer Protocol,超文本传输协议)

是一种*基本的客户机/服务器的访问协议。浏览器向服务器发送请求,而服务器回应相应的网页,用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
2)FTP协议(File Transfer Protocol,文件传输协议)
基于客户服务器模式,FTP协议包括两个组成部分,其一为FTP服务器,其二为FTP客户端,提供交互式的访问 面向连接 ,使用TCP/IP可靠的运输服务,主要功能:减少/消除不同操作系统下文件的不兼容性
3)SMTP 协议(简单邮件传送协议,用户发信到邮件网关的传输协议)
面向连接 的Client/Server模式,
基本功能:写信、传送、报告传送情况、显示信件、接收方处理信件
4)DNS协议(域名解析协议)
DNS是一种用以将域名转换为IP地址的Internet服务。
5)MQ协议(消息队列)
消息从发送者到接收者的方式也有两种。一种我们可以称为即时消息通讯,也就是说消息从一端发出后(消息发送者)立即就可以达到另一端(消息接收者),这种方式的具体实现就是我们已经介绍过的RPC(当然单纯的http通讯也满足这个定义);另一种方式称为延迟消息通讯,即消息从某一端发出后,首先进入一个容器进行临时存储,当达到某种条件后,再由这个容器发送给另一端。 这个容器的一种具体实现就是消息队列。
6)JDBC协议
利用Tcp/Ip协议,是应用层的协议,和FTP,HTTP同一个级别。DBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。

7)WebServices协议使用的是SOAP协议(imple object access protocol,简单对象访问协议)
SOAP协议= HTTP协议+ XML数据格式,Soap建立在http上,是用http传送xml而已;
SOAP是一种简单的基于XML的协议,它使应用程序通过HTTP来交换信息;
SOAP 用于应用程序之间的通信;
SOAP消息的构成:
Ø 必需的Envelope元素,可把此 XML 文档标识为一条SOAP消息;
Ø 可选的Header元素,包含头部信息;
Ø 必需的Body元素,包含所有的调用和响应信息;
Ø 可选的Fault元素,提供有关在处理此消息所发生错误的信息;

diy数据库(八)–客户端和服务器之间的通信协议

一、什么是通信协议

通信协议是指双方实体完成通信或服务所必须遵循的规则和约定。

二、diydb的协议格式

1、协议格式是通信协议中*重要的部分之一,diydb采用的是自定义格式和BSON格式的混合格式

2、协议格式总览

%title插图%num

协议主要分三个大段

(1)协议头:包括消息长度(用于读取一个完整的协议包)和消息类型

(2)协议主体:不同的消息类型对应不同的协议主体,协议主体主要保存的是每种消息类型独有的信息

(3)附加信息:一个或多个bson格式的对象,表示实际操作和返回的数据库中的数据对象

3、协议格式主体

%title插图%num

返回消息:一、返回值,用于表示返回成功或失败;二、返回记录数,用于表示返回的数据对象的个数,即附加消息中bson对象的个                     数。

插入消息:插入记录数,表示要插入的数据对象的个数。

删除消息:因为每次只能删除一个数据,所以这里没有特殊信息。

查询消息:因为每次只能查询一个数据,所以这里没有特殊信息。

注:1)diydb的数据删除和查询时,客户端必须在附加信息中以bson格式传递一个数据对象的_id信息。

2)另外,quit命令只需要协议头就可以了。

4、附加信息

%title插图%num

每个附加记录或插入记录实际上就是一个bson对象,删除条件或查询条件实际上就是{_id:XXX}格式的json对象对应的bson对象(因为diydb实际上没有复杂的条件查询功能,当然可以以后增加)。

注:1)、在直接传递一个结构体对象时,要注意结构体里面的属性的字节对齐。

2)、跨操作系统通信时要注意字节序的问题。

三、源码分析

通讯协议的主要实现(这里主要是数据打包解包)在msg.hpp和msg.cpp两个文件中,比如客户端用msgBuildInsert封装表示插入数据的数据包并存入数据流中,然后服务器端代理线程收到这个数据流后用msgExtractInsert解包这个数据流中的数据。下面是msg.hpp的所有代码。

#ifndef MSG_HPP__
#define MSG_HPP__

#include “bson.h”

#define OP_REPLY 1//返回消息
#define OP_INSERT 2//插入消息
#define OP_DELETE 3//删除消息
#define OP_QUERY 4//查询消息
#define OP_DISCONNECT 6//断开连接消息
#define OP_CONNECT 7//连接消息

#define RETURN_CODE_STATE_OK 1

struct MsgHeader
/*数据包的头*/
{
int messageLen ;//数据包的长
int opCode ;//数据包类型
} ;

struct MsgReply
/*返回数据包*/
{
MsgHeader header ;//数据包的头
int returnCode ;//返回值
int numReturn ;//返回的记录数量
char data[0] ;//标记数具体的开始位置
} ;

struct MsgInsert
/*插入数据包*/
{
MsgHeader header ;
int numInsert ;//插入记录数
char data[0] ;
} ;

struct MsgDelete
/*删除数据包*/
{
MsgHeader header ;
char key[0] ;//删除条件
} ;

struct MsgQuery
/*查询数据包*/
{
MsgHeader header ;
char key[0] ;//查询条件
} ;

/*返回消息的封装*/
int msgBuildReply ( char **ppBuffer, int *pBufferSize,
int returnCode, bson::BSONObj *objReturn ) ;

/*解消息*/
int msgExtractReply ( char *pBuffer, int &returnCode, int &numReturn,
const char **ppObjStart ) ;

/*做一个插入obj的数据包*/
int msgBuildInsert ( char **ppBuffer, int *pBufferSize, bson::BSONObj &obj ) ;

/*做一个插入多个obj的数据包*/
int msgBuildInsert ( char **ppBuffer, int *pBufferSize, vector<bson::BSONObj*> &obj ) ;

/*解插入*/
int msgExtractInsert ( char *pBuffer, int &numInsert, const char **ppObjStart ) ;

/*删除*/
int msgBuildDelete ( char **ppBuffer, int *pBufferSize, bson::BSONObj &key ) ;

/*解删除*/
int msgExtractDelete ( char *pBuffer, bson::BSONObj &key ) ;

/*查询*/
int msgBuildQuery ( char **ppBuffer, int *pBufferSize, bson::BSONObj &key ) ;

/*解查询*/
int msgExtractQuery ( char *pBuffer, bson::BSONObj &key ) ;

int msgMultiInsert ( char **ppBuffer, int *pBufferSize, bson::BSONObj &obj ) ;

/*做一个插入多个obj的数据包*/
int msgBuildInsert ( char **ppBuffer, int *pBufferSize, vector<bson::BSONObj*> &obj ) ;

#endif

对上面函数的实现,我们以插入数据包的封装和解包为例来分析

int msgBuildInsert ( char **ppBuffer, int *pBufferSize, BSONObj &obj )
{//只插入一个数据
int rc = DIY_OK ;
int size = sizeof(MsgInsert) + obj.objsize() ;//表示插入数据的数据包的长度
MsgInsert *pInsert = NULL ;
rc = msgCheckBuffer ( ppBuffer, pBufferSize, size ) ;//如果*ppBuffer指向的堆空间不够用,则重新分配一个足够的字节数组空间
if ( rc )
{
PD_LOG ( PDERROR, “Failed to realloc buffer for %d bytes, rc = %d”,
size, rc ) ;
goto error ;
}

pInsert = (MsgInsert*)(*ppBuffer) ;//将字节流划分成包格式
// 构建协议头
pInsert->header.messageLen = size ;
pInsert->header.opCode = OP_INSERT ;
// 构建协议主体
pInsert->numInsert = 1 ;
// 构建附加消息,即填bson对象
memcpy ( &pInsert->data[0], obj.objdata(), obj.objsize() ) ;
done :
return rc ;
error :
goto done ;
}

int msgExtractInsert ( char *pBuffer, int &numInsert, const char **ppObjStart )
{
int rc = DIY_OK ;
MsgInsert *pInsert = (MsgInsert*)pBuffer ;
// 检测数据包的长度是否合法
if ( pInsert->header.messageLen < (int)sizeof(MsgInsert) )
{
PD_LOG ( PDERROR, “Invalid length of insert message” ) ;
rc = DIY_INVALIDARG ;
goto error ;
}
// 检测数据包的类型对不对
if ( pInsert->header.opCode != OP_INSERT )
{
PD_LOG ( PDERROR, “non-insert code is received: %d, expected %d”,
pInsert->header.opCode, OP_INSERT ) ;
rc = DIY_INVALIDARG ;
goto error ;
}
// 解析附加信息,即取出bson对象
numInsert = pInsert->numInsert ;
// object
if ( 0 == numInsert )
{
*ppObjStart = NULL ;
}
else
{
*ppObjStart = &pInsert->data[0] ;
}
done :
return rc ;
error :
goto done ;
}
注:客户端得到的bson对象的由来:用户在客户端输入命令,这个命令如果包含json格式的文本,则通过json库根据表示json格式的文本构建一个json对象,然后通过bson库将这个json对象转换成一个bson对象。

四、总结

1、因为tcp通信是字节流,并没有边界标识,所以应用层在传数据时,必须通过增加数据包长度字段或者增加数据包边界标识来区分一个完整的包。diydb中用的是数据包长度的方式,这也是实际应用中常用的方式。
2、如果在通信时直接传结构体数据,则要注意字节对齐机制,所以要合理安排结构体中属性的长度的排列顺序。

 

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速