由于是通用传输平台,所以必须有个通用的接口定义。同时由于通用,所以我们需要摒弃各个平台、各种实现的差异。
首先,我们归纳下各种传输平台的共性。一个传输行为的发生,会有几个动作发生:
1、固定监听点的存在,不论UDP或者TCP还是其他,总之,有个点来捕获传输数据。
2、传输通道的存在,显然,没有通道,传输不可能完成。
3、传输过程发生,发送、接收、异常事件的发生。
其次,我们需要分析下已经存在的各种IO模型,比如select/poll/epoll/iocp/kqueue。这些为了高效完成IO,都被集成 到较靠近内核的地方,所以采用他们,一般更容易获得高效率。我们要做的是,尽量将他们封装成一个统一接口。另外,我们知道这些模型为保证高效率,都尽可能 地采用事件模式。
但是,事件模型有个很大的问题,就是事件本身不能等待,所以在上下文关系要求比较紧密的应用环境下,失去对过程的把握。有2个解决方案,一个是增加状态机,这个方案在《事件模型、状态机在高性能网络IO中应用 》中做了一定的论述,另外一个方案,就是必须增加阻塞模式,这个和高性能模型有冲突,只能适用于部分应用场景,应该小心应用,但更容易理解和编程。
我们将整个传输平台定义为vtp,每个传输接口定义为intf,而传输链路定义为link。用操作系统来理解的话,可以将vtp视为一个操作系 统,intf就像网卡,而link就像是传输通道。每个操作系统可以有多个网卡,而每个网卡可以有多个传输通道,每个传输通道必然有2个端,本地端和对 端。
虽然理解上是将vtp作为一个操作系统,但实际上vtp应该是所有socket通讯的集合,这是有区别的。 intf是每个本地主动建立的socket,比如建立一个监听端口,或者连接到远端的套接字,监听端口得到的socket句柄并不是intf,而归到 link去。link是每个用于传输的句柄,包括accept和connect,以及udp相关的。
我们为vtp建立api接口包括:
1、vtp_init(vtp_t *vtp) ;
2、vtp_final(vtp_t *vtp) ;
3、vtp_wait(vtp_t *vtp , int timeout);
4、vtp_async(vtp_t *vtp);
接口1和2比较好理解,接口3是因为如果没有IO的时候,必须等待,不然就需要sleep来保证vtp不会一直死循环来轮询。而接口4是让vtp异步执行,默认情况下,vtp是同步,也就是说,在主线程中不断调用vtp_wait,这样,单线程的应用就 比较容易写。
为intf我们设计这样的接口:
5、intf_t *vtp_add_intf(vtp_t *vtp , int proto , int port , int option) ;
6、int vtp_del_intf(vtp_t *vtp , intf_t *intf) ;
7、link_t *intf_conn(intf_t *intf , const char *ip , int port) ;
接口5、6、7比较好理解,增加和删除intf,以及连接远处的IP/PORT。我们知道,端口可以被连接,也可以发出连接,因此,intf_conn是必须的,intf_conn中intf是vtp_add_intf的返回值,vtp_add_intf中,参数port必须指定为0。
为link我们设计这样的接口:
8、link_lock(link_t *link) ;
9、link_unlock(link_t *link) ;
10、link_send(link_t *link , const char *buf , int len) ;
11、link_recv(link_t *link , char *buf , int len) ;
12、buff_t *link_buff_alloc(link_t *link);
13、buff_t *link_buff_pop(link_t *link) ;
14、int link_buff_free(link_t *link) ;
15、int link_buff_push(link_t *link , buff_t *buff) ;
16、int link_close(link_t *link) ;
我们知道,在高性能服务器中,会有大规模的数据传输,如何减少内存数据拷贝对 提高性能很重要。link_lock/link_unlock,主要是为了能够保证一个报文被分成多次发送时,不会被中间插入其他数据。link_send/link_recv这2个函数是阻塞的,需要拷贝缓冲区内容,但由于是阻塞模式,所以编程上比较方便。link_buff_alloc实际上直接从内存中分配缓冲区,供外部程序直接使用,然后通过link_buff_push提交到发送缓冲区,这样就不需要拷贝数据。link_buff_pop是从link缓冲区中弹出可用的数据,而link_buff_free则是释放buff,包括link_buff_alloc或者link_buff_pop的。