【深入浅出Linux网络编程】 "开篇 -- 知其然,知其所以然"
【深入浅出Linux网络编程】是一个连载博客,内容源于本人的工作经验,旨在给读者提供靠谱高效的学习途径,不必在零散的互联网资源中浪费精力,快速的掌握Linux网络编程。
连载包含4篇,会陆续编写发出,欢迎持续关注,分别如下:
1,开篇 -- 知其然,知其所以然
2,基础 -- 事件触发机制
3,实践 -- TCP & UDP
4,应用 -- 基于轮子造汽车
该连载博客假设读者对Linux网络编程充满了学习兴趣,并且清楚的明白学习Linux网络编程能够解决什么问题,从而可以将博客重点放在内容本身,而不是泛泛的概念普及。
【懵懂】在学习博客之前,你对网络编程的认识也许是这样的(至少曾经是这样的):
int main() { while (1) { fd = accept(); while (1) { request = recv(fd); ... ... send(fd, response); if (fd has error) break; } close(fd); } ... ... ... }
这段代码在main函数中执行, 只能管理一个连接, 除非这个连接断开才会处理下一个连接,实在太糟糕了。
【青涩】为了改变这个糟糕的现状,你也许会试着在这个实现的基础上进行拓展,代码看起来是这样的:
void *thread(void *arg) { int listen_fd = *(int *)arg; while (1) { fd = accept(); while (1) { request = recv(fd); ... ... send(fd, response); if (fd has error) break; } close(fd); } ... ... } int main() { int listen_fd; ... listen(listen_fd); for (0..10) { pthread_create(thread, &listen_fd) } ... ... }
这段代码中,你将原本main中的代码粘贴到了线程函数里,然后启动了若干个线程执行处理,程序同一时刻能够处理的连接数不再仅限于1个了,启动10个线程就可以支持10个连接在线,的确很奏效。
在这个设计下,为了支撑10000个连接同时在线,你需要启动10000个线程,是否可行呢。线程是需要由一颗CPU执行指令才能运转的,如果你的计算机只有2个CPU核心,那么同一时刻其实只能执行2个线程,其他9998个线程其实都在等待CPU资源。
Linux内核是分时系统,会保证给每一个线程都一小段时间片去执行代码,这个时间片必须足够短才能保证所有线程都及时得到执行以便对用户看来像是真的并发处理一样。CPU从一个线程执行切换到另一个线程执行是需要保存各种执行上下文的,需要花费一定的时间。
可以想象10000个线程争夺2个CPU的惨烈情景,线程切换花费的时间比线程获取的时间片还要长,带来的代价就是系统好忙,响应好慢,这太悲剧了!
举这两个例子,相信能代表绝大多数学习网络编程同学的学习足迹。在这个槛上,你迷茫过停留过试着突破过,听到过“异步”,“高并发”,“select”,“epoll”等等词汇,搜寻过各种博客,书籍去学习这些知识,但绝大多数介绍都太粗糙,根本无法指导实践。
【成长】跟随本系列博客,你将顺利的掌握Linux网络编程,并且有实实在在的网络库代码可以效仿学习,上面的问题将不再困扰你,让我们从“基础 -- 事件触发机制” 开始吧~