网络编程小结

写这个小结主要是因为之前研究Boost.Asio的时候,其内部使用了很多不同的方法来实现异步网络编程 然后就顺便把一些高级的玩意看了一下,也顺便把以前低级的玩意放到一起,哇哈哈。很多东西只是个人的理解,不一定正确

Socket嘛,最早是在Unix上被设计出来的,所以Unix上嘛,显然性能要好一点点。

最早接触的网络编程应该是阻塞型Socket吧,就是所有操作都等操作完成了才干下面的事 这样的话如果是很多很多连接,那就要有很多很多进程,如果1万条连接,那么CPU除了线程资源调度,其他就不要干什么事了

所以就来了非阻塞型Socket这种Socket操作是立即返回滴,但是由于socket数据是在内核态,所以每次要枚举所有的socket,才能知道有没数据。so,如果连接数一多,也就只能在系统调用间穿梭来,跑回去。

所以,就来了后面的IO复用机制。

IO复用里,最简单的应该就是select了吧,select是同步IO复用机制 这个操作在Windows下和Linux下都支持。使用上基本一样,但是还是有一点点小区别。之前写了个适配的东东,可以参照下 https://github.com/owent-utils/c-cpp/tree/master/src/Socket 其实select和非阻塞型Socket的自己轮询差不多,但是是在内核态完成的,所以效率稍微高一点。但是有socket可用的时候,会发生数据拷贝,把数据copy到用户态里来。 而且select受进程打开文件个数的限制,一般是1024或者2048,应该很少有BT人物和我们这开发机一样把文件个数设为好几十万的吧。 而且select每次也是每个socket枚举一遍的,然后sleep一下,再枚举,所以连接数高了以后,性能急剧下降。

接下来就是poll,也是同步IO复用机制 他的实现原理和select一样,就是改成了由系统通知用户关心的事件,没了打开文件个数的限制。但是也是内部枚举,所以连接数高了以后,效率仍然存在问题。

再接下来就是epollkqueue了,这两个也都是同步IO复用,但是他们是基于事件的,Linux里有epoll,FreeBSD里有kqueue 他们都是向系统注册关系的事件,然后系统在事件发生是返回。并且其内部的数据是mmap进内核态的,就少了一次拷贝 epoll和kqueue主要部分是一样的,性能相差也不大 使用epoll的时候,还可以一起使用一个linux内核里比较新的东西,eventfd。这玩意可以用来代替进程锁或者代替管道来进行进程或线程间的事件通知,简化了很多操作的说。eventfd会创建一个可以被read和write的描述符,拥有一个uint64_t型的计数器,每次write的时候都是累加的,read的时候把累加的值读出来,所以每次读写都是8字节数据。 并且read时如果eventfd里的计数为0,操作就会阻塞。在释放的时候,一个eventfd的所有句柄都被释放时,资源才会被销毁。类似引用计数,比较Nice。 详见 http://man7.org/linux/man-pages/man2/eventfd.2.html 用epoll+eventfd来实现Boost.Asio的全异步IO,轻松+愉快啊。

其实还有一种操作是 /dev/poll 但是我想偷个懒,就没看这个玩意。好像区别不太大,就是用了 /dev/poll 这个驱动来完成事件响应

最后一个就是Windows下的全异步IO复用模型的IO Complete Port了 详细说明看这里 [http://msdn.microsoft.com/en-us/library/windows/desktop/aa365198(v=vs.11).aspx](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365198(v=vs.11).aspx) 微软的说明书太绕了,所以示例看这里 http://blog.csdn.net/likexx/article/details/5222762 和前面的epoll和kqueue不一样的是,IO Complete Port可以拿来管理一个线程池(通过某接口把线程block掉的方式),在IO可用时数据下发到某个线程里操作。 这个使用流程基本和Boost.Asio一样,只是Asio在外面有加装了一层io_service来管理所有服务。他们的回调都可以是异步的。所以也省了一些自己写线程调度的麻烦

这篇总结写得比较乱,也懒得整理了。仅是写个小总结,普及一下知识。

Last updated