首页 存档 技术 查看内容

Windows服务端程序向Linux平台移植事项 一、数据类型定义 二、进程间的通信 三、定时 ...

2018-3-30 13:00 |来自: 互联网 308 0

摘要: 本文选自《开发者头条》4 月 19 日用户分享,感谢作者 nicol_tao 自荐。 头条不止是阅读,还有分享,更有IO币。可以兑换机械键盘、技术图书喔。 欢迎分享:http://toutiao.io/contribute 前面做了一些Windows服务 ...

本文选自《开发者头条》4 月 19 日用户分享,感谢作者 nicol_tao 自荐。

头条不止是阅读,还有分享,更有IO币。可以兑换机械键盘、技术图书喔。


欢迎分享http://toutiao.io/contribute

前面做了一些Windows服务端程序向Linux服务端程序的移植工作,还是有些收获的,这里整理记录一下,将工作内容和细节方面的东西供大家参考。同时需要说明几点:这里的移植是真的移植,而不是考虑跨平台开发型的;这里的移植是针对无界面形式的程序,主要是服务端程序;那啥wine、mono的太大,就不考虑了。


一、数据类型定义

1.1 数据类型的差异

Windows和Linux的数据类型定义完全是两个风格,而且Windows的类型定义喜欢用大写字母,Windows的数据类型主要是定义在windef.h这个头文件里面的,可以将简单的数据类型按照目标机器翻译过来,当然也有些定义比较的复杂,不过很多却是没用的,可以安全的删掉。


1.2 函数接口的差异

Windows也是支持POSIX标准的,所以大多数的底层函数还是可以用的,但是某些函数的名字和参数签名等还是有些差异(比如stricmp/strcasecmp),如果要在这个头文件里面处理,可以内联封装加进去。


二、进程间的通信

2.1 创建线程

Windows使用CreateThread创建线程,而Linux通常使用pthread线程库来实现多线程。


2.2 多线程以及进程间同步

在Windows上面,除了CriticalSection是仅限线程间的同步之外,其他Mutex、Event、filemap,在使用的时候,只要设定了lpName,那么就可以在其他进程中用这个名字打开,就算是进程间的同步和通信了,否则的话就是线程间的同步。

Windows Linux(线程) Linux(进程)
CriticalSection pthread_mutex -
Mutex semaphore semaphore
Event semaphore semaphore
filemap shm、mmap shm、mmap

shm和mmap其实都差不多,但是如果有些数据不像映射到硬盘文件系统上(比如处于保密安全考虑),那么就推荐使用shm来实现。


三、定时器

在Windows下面,调用SetTimer创建定时器的时候可以指定ID,一个进程中可以创建很多个定时器,但是在Linux下就没有这么方便了。alarm/sleep都是用SIGALRM来实现的,而且代码没法异步执行;timer_create可以指定发送的SIGNUM,然后可以利用调用sigaction提供的参数来区别各个定时器,当然是个候选的方式;同时我找到的网络还有推荐的是使用timerfd epoll来实现,本库就是按照这个实现封装来模拟SetTimer的操作。

看似后面两者都可以实现多定时器,实际还是有些差异,前者设定信号处理函数,但是信号处理函数是异步的,所以在这种情况下所做的事情有限,而后者使用一个线程专门检测执行信号处理函数,算是一个进程同步上下文,虽然精度有所欠缺(比如只能按顺序检测没法按照真正时间排序),但是使用更加方便安全。


四、网络IO复用

4.1 数据和函数定义细节差异

Windows针对自己的异步IO添加了一系列的宏,比如WSAEFAULT、WSANOTINITIALISED等,以及WSAGetLastError等函数(这个直接用errno模拟了)。


4.2 网络IO复用

虽然都是事件驱动的网络IO复用技术,但是算是两者网络风格最大的不同了。


4.2.1 Windows平台

Windows采用完成端口(Completion Port)的方式,一般的操作步骤是:
(1)采用CreateIoCompletionPort创建完成端口;
(2)创建bind、listen服务端套接字;
(3)根据服务器的CPU数量,创建一定数目的工作线程,然后在每个工作线程中调用GetQueuedCompletionStatus等待完成事件;
(4)上面函数返回,说明操作系统IO操作已经完成,就可以直接操作数据了。


4.2.2 Linux平台

Linux有经典的select、poll,以及后面增强型的epoll方式,目前epoll有很多优点(侦听socket数目多、效率高等),所以没有特殊利用就用epoll吧,epoll的操作步骤是:
(1)创建服务器侦听socket并实现bind、listen等操作;
(2)设置socket为O_NONBLOCK模式;
(3)创建epoll_event结构,首先将listen的socket加入到侦听当中;
(4)进入event_loop中,调用epoll_wait,如果listen socket有请求,就accept得到链接的n_socket,并把这个n_socket再次添加到epoll侦听中;
(5)以后每次epoll_wait返回,就两种情况:要不listen socket有新连接请求,要么之前连接并侦听的socket有数据请求。
内部的实现细节暂不讨论,其中最大的区别就是,Windows的完成端口用起来十分简单,注册之后,你提供数据存储的地址,然后就等待,一旦返回,说明数据已经接受好并放到指定的位置了,用户只需要专注数据处理了;Linux繁杂但是灵活,而且epoll可以设置Level/Edge触发,应对不同网络负载情况。


五、其他方面

5.1 调试技术

有时候程序写多了,莫名其妙的Segmentfault,如果没有调试信息会让人一脸萌逼不知所措。针对这类情况,可以:
(1)编译的时候添加-g调试参数,产生函数符号;
(2)系统启动coredump支持,这样产生fatal错误的时候,会生成错误转储,用gdb可以调试之;
(3)发生段错误会产生SIGSEGV信号,可以在程序开始的时候,将这个信号处理函数挂靠在特定的处理函数中,在函数中使用backtrace_symbols来回溯调用链。


5.2 单链表

Linux内核有个大名鼎鼎的list_head,可以封装在数据结构中使用,十分方便。但是这东西默认是内核态的,所以做了一点点修改,就可以在用户态方便的使用了。

移植的代码已经托管到st_utils了,欢迎大家测试指正。同时由于工作的时间比较的旧,很多参考文献不能一一列出了,如原作者有需求,请联系我加上!

本文完!


参考文献

更多优质内容,欢迎安装、使用《开发者头条》iOS、Android 客户端。

体验地址http://toutiao.io/download

本文转载自:微信公众账号 - developerWorks,版权归原作者所有!

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部