上个月按项目业务功能的新需求,需要实现一个简单的服务程序,对接前台客户端和后台的业务处理端。
之前存在一个windows平台对接端,使用IOCP通信模型来实现。而现在的需求是要在Linux服务器上进行实现,所以采用的是epoll模型。
这次的的实现周期大概是一个月的时间,主要是采用模仿的方式来做,因为在此之前对于网络编程这块不是太擅长,重新设计的风险太高,而且不能保证能够按时的完成项目计划。所以,花了半个月的时间阅读windows下的对接端源码,简单分析了一下大概的通信处理方式,这些工作做完之后,概要设计就算是基本做完了。
之后,花了一周左右的时间完成通信框架的编码,最后一周左右的时间主要用来实现命令的对接。
这次算的上是网络编程的一个小的尝试,结局还算圆满,希望能够还能有更多的尝试机会。
开发过程中遇到的一些问题:
1. 结构体对齐
前端传入的数据形式是多种多样的,有可能是xml文件,有可能是结构体。当传入的数据是结构体的时候,需要保证结构体对齐方式一致,不然可能会出现数据长度不一致的情况,造成数据的解析失败。
可以采用的方式是设置结构体的对齐方式:
#pragma pack( push, n )
/*
** define the struct
** …
*/
#pragma pack( pop )
2. 数据丢失
因为每次前台发送的命令长度不一致,而对接端的接受缓存长度是一样的。这样的话,可能会出现一下几种情况:
1) 因为前台传入的命令比较短,并且一次发送了多个命令,对接端缓存一次接收到了多个命令;
2) 因为前台传入的命令太长,造成对接端缓存不能一次性接收到完整的命令;
如果每次收到数据,仅仅针对接收缓存的数据处理一次,就有可能造成一些命令丢失【可能是因为命令隐藏在前一个命令的后面,即情况1);可能因为命令格式错误,即情况(2】
可以采用的方式是,维护一个数据结构,将每次接收到的数据依次放入连续的地址空间里面,然后依次解析命令。
采用这种方式,需要注意一些问题:
1) 必须清除每条命令的长度,可以在定义报文格式的时候用一个字段进行记录;
2) 维护的这个数据结构对于每个连接是唯一的,保证接收到的数据能正常拼接;
3) 每次处理完一个命令之后,需要检查该结构体,保证接收到的完整命令都已经处理完成;
3. 重复包含头文件
因为在定义头文件的时候使用了预编译指令#ifndef,所以在包含头文件的时候有些肆无忌惮,然后就产生了.h和.cpp文件里面包含了同一个头文件的情况,有时候这种情况可能不太明显,因为那个相同的头文件不是直接包含的,而是隐藏在别的头文件里。
开始的时候好像没什么问题,当我在那个共同包含的头文件里,定义新的结构体或者宏的时候,再次进行编译的时候,编译器会报出找不到新结构体或宏的定义(经过很多次的确认和排查,结构体名字没有输错,makefile没有写错)。
当将可能的重复头文件去除之后,整个编译就很顺利了。
在检查重复包含这种情况的时候,觉得有个方式可以尝试一下:
(makefile)
……
.depend: *.cpp
rm–f .depend
g++-std=c++11 –MM $^ >.depend
……
编译器会生成源文件的依赖文件列表,并输出到.depend里面,通过查看.depend文件可以很明显的看到重复包含的头文件。
不过,当检查完成之后,一定要将这三行从makefile去掉,不然编译起来慢的实在是太吓人了。