网络通信服务器小型框架 描述

这是我参考mqtt服务器m

1,定义协议MQTT

类型长度数据checkSum
Typelenghtbin data~sum

2,数据结构

struct MqttPacket { //定义Mqtt数据包
	int type;  //MQTT数据包首定节
	int remlength; //Mqtt数据包内容长度
	int8_t *remdata; //Mqtt数据内容
	int _read_remlensize; //remlength占用字节数
	int _read_remsize; //remdata占用字节
	int _read_pos; //读取位置
};

3,收发逻辑

当遇到EAGAIN或EWOULDBLOCK等信号中断读取时返回为0,表示数据读取完成,下次来读的时候继续读

读取时(mosquitto就是这样读的):
//返回-1为断开,返回0表示读取成功(不一定读取完数据包哦)
int loop_handle_read(int fd, struct MqttPacket *inPacket) {
	int rlen;
	uint8_t byte;
	if (inPacket->type == 0x00) { //读头:因为不会等于0x00
		rlen = read(fd, &byte, 1);
		if (rlen == 1) 
			inPacket->type = rlen; //下次读就不会读头
		else if (rlen == 0)
			return -1;
		else if (errno == EWOULDBLOCK || errno == EAGAIN)
			return 0; //读取不到,但不断开
		else
			return -1; //断开
	}
	if (inPacket->_read_remlensize <= 0) { //读可变长度
		do {
			rlen = read(fd, &byte, 1);
			if (rlen == 1) {
				inPacket->_read_remlensize--;
				if (inPacket->_read_remlensize == -1)
					inPacket->remlength = byte & 0x7F;
				else
					inPacket->remlength |= (byte & 0x7F) << 7;
				if (inPacket->_read_remlensize <= -4)
					break;
			} else {  //与上面相同不写}
		} while (inPacket->_read_remsize <= 0);
		inPacket->_read_remsize *= -1; //负负得正,下次就不再读可变长度了
		inPacket->remdata = malloc(inPacket->remlength);
		inPacket->_read_remsize = inPacket->remlength;
		inPacket->_read_pos = 0;
	}
	while (inPacket->_read_remsize) {
		rlen = read(fd, inPacket->remdata + inPacket->_read_pos,
				inPacket->_read_remsize);
		if (rlen > 0) {
			inPacket->_read_remsize -= rlen; //当读取完后: _read_remsize一定为0
			inPacket->_read_pos += rlen;
		} else {  //与上面相同不写}
	}
	//到此一个数据包就读取完成了
	// 做数据包处理功能 
	//清空下面两个数据就会再读取
	inPacket->type=0;
	inPacket->_read_remlensize=0;
return 0;
}

4,处理分离

 

5,协议栈处理逻辑

通信协议栈(单工通信-不是C代码,回调方式-用C须要很多代码), 依据这种原理可以满足所有协议要求

基本协议:
Request:请求:[funid][data];

Response:响应[funid][YES/NO]; ACK:回应
封装:  
方式一:

sendRequest(data) {  send(fd,data...); } //发送请求数据
sendRequestWaitResponse(funid,data)  //发送请求等待响应
{   
    sendRequest(data);
    do{ 
      recv(fd,rdata.);
      if(rdata.funid==funid) return rdata.result[YES/NO]; //接收响应,是否成功
      if(rdata.type==REQUEST) appendRequest(data); //添加到请求队列
    while(time<10); //自己设定时间
}
readData() {  //接收数据   
   if(data.type==REQUEST) 
        appendRequest(data); 
.....
 } 
appendRequest(data) { //追加请求数据,如果在发送请求时收到对方的请求
    queueFrame.app(data);
} 

requestHandle() //处理对方的请求数据

深入实现逻辑(使用回调函数, 单线程逻辑处理):
数据帧: FuniD=0x02时的协议格式:[id][commandclass] [cmd] [data]
发送方用请求发送后,接收方以请求回应,id表示哪个设备
当commandclass==0x80代表是一个加密层,其数据内容才是须要的.

Queue queue_app, queue_raw; //两个队列,表示应用层数据,原始层数据

/**
 *scheme表示在哪一层: 0:原始层,1:加密层; callback为回调,发送结果
 *参数放入应用层队列,发送完后回调
 */
app_send(id,data[cls,cmd,...],scheme,callback(int)  ||arg ) { queue_app.append(arg); }

/**
 *加密层发送,发送完后回调
 */
_send_crypt(id,data[...],  c_callback(int):arg  ) {  //注意这里有回调函数(在下面的回调函数中调用)
    cdata[0x80,AES,`password`]; //发送加密说明
    _send_raw(id,cdata, toraw_callback(int){ //有点像object-c
                         _send_raw(id, encode(data), c_callback:arg ); ///原始层发送完成之后的回调到这来,发送加密数据
      });
}
/**
 *原始层发送,参数上下文放入原始层队列,发送完后由原始层回调
 */
_send_raw(id,data[...],callback(int)) {
      queue_raw.append(args[id,data,callback]); //添加到原始层发送队列
}

/// 处理应用层数据(核心实现)
handle_app() {
   arg=queue_app.pop(); //从队列中得到数据
   if(arg.scheme==0) _send_raw(args[id,args.data,callback]); //原始发送
   if(args.scheme==1) _send_crypt(args[id,args.data,callback]); //加密发送
}
/// 处理原始层发送(核心实现)
handle_raw() {
   arg=queue_raw.pop();
   ret=sendRequest(arg[id,cls,cmd...]);  //这里,发送并等待结果
   arg.callback(ret:true,arg); //回调发送是否成功的结果
}

则,在单一线程里面只需要

while(1) {  handle_app(); handle_raw(); }

然后,你只需像queu_raw或queue_app队列扔数据就可以了


//如果: cmd=Get 须要对方cmd=Report, 对方回来数据后到 callback回调函数位置

app_send_get(id, data[cls,cmd:Get,..], wait[cls,cmd:Report], callback(status, data:report)){
        app_send(id,data,scheme=auto, _get_backfun(){//发送到应用层
                              //应用层发送成功后,回调这里,存在请求队列
                             list_request.append(wait, _report_backfun(status,data:report){
                                           callback(status, data:report); //回去了
                             });
         });
}
handleRequestFrame(){ //处理数据帧
    frame=queueFrame.pop(); //看appendRequestFrame
    list_request.pop(frame.id,frame.cls, frame.cmd, _sucess(wait, _report_backfun) {
                     _report_backfun(YES, frame.todata); //这样就回去了
     }
   }
}

 

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值