IT技术博客大学习 共学习 共进步

标签:网络编程

共 46 篇相关文章

IT 累计浏览 6

扫描全国的公网IP需要多久?

作者基于个人兴趣,在一台旧款4核迷你主机的家庭网络环境下,测试了扫描中国大陆所有公网IP地址的耗时。最终扫描约3.43亿个地址,发现其中约592万个IP可达,总耗时约1小时2分58秒。该测试旨在探索使用单台设备探测全国范围内运营商与云服务商网络连通性、识别故障或劫持情况的技术可行性。 文章核心是介绍了一款由作者重构的网络扫描程序的实现。新版本摒弃了之前依赖libpcap库的gopacket方案,完全基于Go标准库中的icmp与ipv4扩展包构建,无需启用CGO,便于部署与编译。程序架构采用并发模型,主要由三个goroutine协作:一个负责解析APNIC提供的IP网段列表并分发任务;一个负责批量构造并发送ICMP回显请求报文;一个负责监听并接收ICMP回显应答,最终将存活IP输出。代码通过设置BPF过滤器优化性能,并使用进程ID作为ICMP报文标识以准确匹配响应。整个扫描引擎仅约200行代码,展示了使用Go语言进行高效网络编程的典型范例。

IT 累计浏览 1,502

Python UnicodeEncodeError问题的分析和思考

这篇讲的是作者在用Python爬取网络数据时频繁遇到的一个棘手问题:程序会因 `UnicodeEncodeError` 意外中断,报错指向一个无法编码的特殊字符 “·”(Unicode码点 u+2022)。问题的直接诱因是远程文件包含了本地编码无法表示的字符。 文章没有止步于解决问题,而是深入Python的“内核”,系统梳理了编码处理的全流程。作者解释了Python 2中字符串对象(str与unicode)的本质区别,以及它们如何受源文件编码和系统控制台编码(如Windows下的GBK)的影响。通过 `encode` 和 `decode` 的示例,厘清了编码转换的基本逻辑。 最关键的部分在于对输出环节的剖析。文章指出,`print` 语句会调用 `sys.stdout` 这个 `TextIOWrapper` 对象,它默认使用终端编码(如GBK)对unicode字符串进行 `encode`。当字符(如 u+2022)不在目标编码的码表中时,异常便产生了,这也解释了为何同样的代码在GBK终端的Windows上报错,而在通常使用UTF-8的Linux上却能正常运行。文章从IO层和编码映射原理上,把这个常见错误的来龙去脉讲得非常透彻。

IT 累计浏览 4,584

在Linux进行IO的正确姿势

很多C/C++程序员在做网络编程时,习惯使用封装好的库,却可能忽略了底层IO操作的一个常见陷阱。这篇文章指出,许多人对read()/write()函数的错误处理并不到位。 作者从一个典型的错误代码示例出发:检查返回值为-1或0就认为完成了处理。但这忽略了关键的errno判断,尤其是EINTR(系统中断)和EAGAIN(非阻塞IO暂无数据)这两种情况。文章进一步展示了,仅仅判断errno还不够,正确的姿势是将IO操作放在一个while循环中,以便在发生可恢复的中断时进行重试,而非直接退出。 文中强调,一个完善的IO处理逻辑必须能应对操作系统的瞬时状况,并结合了select/epoll等IO多路复用机制。最后,文章建议读者参考sim框架的开源代码,学习成熟的IO处理模式。

IT 累计浏览 4,142

构建C1000K的服务器(1) – 基础

当C10K问题已成为历史,作者将目光投向了更宏大的C1000K挑战。对于Twitter、微博这类需要维持千万级实时连接的平台,单机百万连接(C1000K)的能力能极大降低服务器集群规模。 这篇文章并没有直接给出某个框架或库的解决方案,而是从根源出发,剖析了限制C1000K实现的四大核心因素。作者以Linux为例,深入讲解了如何突破操作系统默认的“最大打开文件数”限制,给出了包括临时修改(ulimit)和永久配置(sysctl.conf, limits.conf)在内的具体方法与命令。文章还通过一个原始的C语言服务器程序,实际测量并验证了操作系统为维护百万连接所消耗的内存,将理论估算与实际开销结合起来分析。 作者强调,解决C1000K问题不能盲目追求新技术,而应先理清操作系统内核、内存分配与网络吞吐这些底层瓶颈。文中的系统参数配置和测试思路,为需要应对海量并发连接的开发者提供了切实可行的排查起点和优化依据。

IT 累计浏览 4,382

再叙TIME_WAIT

这篇文章从一次“被反复问到”的经历出发,全面梳理了 TCP 协议中的 TIME_WAIT 状态。作者首先用几条简单的 Linux 命令,带我们直观感受繁忙服务器上动辄数万的 TIME_WAIT 连接。文章的核心在于解释了这种状态存在的“必要性”:它通过等待两倍的报文最大生存时间(MSL),确保双向关闭握手的数据包不会在不可靠的网络上引发混乱或干扰新连接。 接着,文章深入对比了控制 TIME_WAIT 数量的几种主流内核参数调优方案。其中,`ip_conntrack` 虽能调整超时,但作者指出它带来的性能下降可能得不偿失。而广为流传的 `tcp_tw_recycle` 参数则隐藏着一个在 NAT 环境下可能导致连接失败的“时间戳陷阱”。相比之下,`tcp_tw_reuse` 被认为相对安全,但其关键限制在于仅对连接发起方(如作为客户端的 PHP)有效,且依赖时间戳递增机制。 整体来看,这篇文章不是在简单罗列解决方案,而是深入剖析了问题的成因与各种方案的权衡。它提醒我们,那些试图强行缩短 TIME_WAIT 的“快捷方式”往往伴随风险,而理解其设计原理,才能为一次连接的优雅退场赋予合理的等待时间。

IT 累计浏览 4,121

TCP网络协议以及其思想的应用

这篇深入探讨了TCP协议核心思想的文章,跳出了单纯的网络协议讲解,聚焦于如何将TCP在不可靠网络上构建可靠传输的智慧,活用到更广泛的系统设计中。 作者从大多数程序员对TCP的熟悉但未必精通的状态切入,明确指出TCP的精髓是在IP层的不可靠传输之上建立可靠机制。其核心技术如滑动窗口、慢启动、指数退避等,目的都是优化传输。但更重要的,是它提供的设计范式。 文章强调,TCP的“可靠”是相对自身协议栈而言的,一旦跨越不同系统边界(比如从一个应用到另一个应用),就需要重新审视可靠性。因此,任何涉及通信与交互的场景,都可以借鉴TCP的思想。 作者提炼出了在任何通信系统之上构建可靠传输所必须的三要素:确认、重传和顺序。这为我们设计自定义可靠协议(例如在UDP之上)或解决复杂交互问题,提供了清晰且根本的思路。

IT 累计浏览 2,762

HAProxy的event_accept函数源码分析

这篇讲的是HAProxy核心组件event_accept函数的源码深度剖析。面对HAProxy复杂庞大的代码库,作者直接指出其函数动辄数百上千行的“代码风格问题”,并选择以event_accept函数为例,通过主动重构来拆解分析,让逻辑脉络清晰起来。 文章将函数执行流程系统性地拆解为六个关键步骤:从接收连接后,首先检查连接数与文件描述符是否超限;接着设置客户端socket的非阻塞、TCP优化等属性;然后从内存池分配新会话(session)并初始化状态;再分配处理任务(task)并绑定回调函数;最后分别配置会话的客户端与服务端流接口(stream interface),为后续数据转发做好准备。 作者不仅逐步解读了每个步骤的代码逻辑,更通过调整代码顺序和重组变量,呈现了一个更清晰、更模块化的实现思路。这种分析方式让读者能跳过原始代码的冗余,直接抓住HAProxy处理新连接时,在资源分配、状态初始化与任务绑定方面的核心设计逻辑。

IT 累计浏览 2,281

Erlang集群全联通问题及解决方案

这篇讲的是Erlang集群一个看似“贴心”但可能致命的设计:默认全联通。 作者从Erlang集群节点加入时的“引荐”机制讲起,新节点会被介绍给所有现有节点,从而建立一个完全连接的网状拓扑。问题在于,这种全联通连接数(N*(N-1)/2)会随节点数增加而爆炸式增长,不仅消耗大量系统资源,更因定期的心跳检测引发网络风暴,严重制约集群规模。 解决这个问题的方案出人意料地简单:在节点启动参数中加入“-hidden”标志,使其成为“隐藏节点”。如此一来,节点间的连接不会被主动发布,从而有效避免了不必要的全联通。 不过,作者特别提醒了一个关键细节:隐藏节点的行为是“或”逻辑——只要通信双方中有一方是隐藏节点,global模块就不会进行自动引荐。这个特性在实际部署和故障排查时必须留意。文章最后指出,社区已开始正视并规避这一设计带来的问题,对从事大规模分布式Erlang开发的工程师来说,这个经验颇具价值。

IT 累计浏览 1,584

gen_tcp接收缓冲区易混淆概念纠正

这篇讲的是 Erlang/OTP 中 `gen_tcp` 模块几个缓冲区参数之间的常见混淆。很多开发者看到 `buffer`、`sndbuf` 和 `recbuf` 这三个选项时容易困惑:它们到底是什么关系?文档的简要说明往往不足以理清头绪。 作者选择直接深入 C 驱动层源码(`inet_drv.c`)来寻找答案。通过分析 `inet_set_opts` 函数的实现,文章揭示了核心事实:`sndbuf` 和 `recbuf` 设置的是内核 Socket 层的发送与接收缓冲区大小,这符合常规理解。而 `buffer` 选项则完全不同,它设置的其实是 Erlang VM 内部、应用层用于暂存从 Socket 读上来的原始数据的缓冲区大小提示(`desc->bufsz`)。 文章一个巧妙的发现是,源码中存在自动调整逻辑:当显式设置 `sndbuf` 或 `recbuf` 后,`buffer` 的值会被自动更新为两者中的较大值,以确保应用层缓冲区足够容纳内核传上来的数据。但其影响范围仅限于接收路径——因为发送数据可以利用队列,无需类似的额外缓冲。 通读全文,它厘清了一个关键结论:这三个参数分属不同层级,`buffer` 专注于控制 Erlang 侧接收数据的临时缓存大小,其默认值和动态扩容策略都围绕接收场景设计,而不直接影响内核的 Socket 缓冲区。对于需要精细调优 TCP 通信性能的开发者,理解这层区别至关重要。

IT 累计浏览 2,321

urllib2源码解读三(探索OpenerDirector的add_handler)

这篇讲的是 urllib2 源码中 OpenerDirector 的 add_handler 方法如何实现 handler 的自动分类。文章接续了之前对 build_opener 的探讨,深入到 add_handler 的内部,揭示了它并非简单存储,而是根据每个 handler 实例所具有的方法,进行智能归类。 核心的实现思路非常巧妙:它不依赖显式的类型标识,而是通过解析 handler 方法名的结构来动态分类。具体来说,代码会遍历 handler 的所有方法,检查方法名是否包含特定模式,例如 `http_error_404` 或 `https_open`。它以第一个下划线为界,前半部分是协议(如 http、https),后半部分是条件(如 open、error_301)。根据这些解析出的信息,handler 会被分别注册到 `handle_open`、`handle_error`、`process_request`、`process_response` 这四个核心字典中,使得后续的网络请求调用链能高效、准确地匹配到对应的处理器。 这种基于“约定优于配置”的动态注册机制,让 handler 的功能与协议、状态码紧密绑定,既保持了扩展的灵活性,又确保了内部调用的有序性,是 Python 标准库设计中的一个典型范例。

IT 累计浏览 2,621

urllib2源码解读二(简单的urlopen)

这篇文章从大家最熟悉的 `urllib2.urlopen('http://python.org')` 这行代码出发,带我们潜入Python标准库的源码内部,探索一个简单HTTP请求背后的构建机制。 作者揭示了一个巧妙的设计:`urlopen` 在首次调用时,并不会重复创建连接对象,而是通过 `build_opener` 函数构建一个全局的 `_opener` 对象。后续的所有请求都复用这个对象,从而避免了频繁初始化的开销。这个 `_opener` 本质上是 `OpenerDirector` 的实例,它像一个项目经理,内部通过几个关键的字典(如 `process_request`、`handle_open`、`process_response`)来管理众多功能各异的“处理器”(handler)。 文章重点剖析了 `build_opener` 函数的运作:它先初始化一个 `OpenerDirector`,然后将一系列默认的 handler 类(如 `ProxyHandler`、`HTTPHandler` 等)注册进去。整个过程清晰地展现了 urllib2 高度模块化的架构——通过组合不同的 handler 来构建功能强大的 opener,使得网络请求的处理流程灵活且可扩展。这让读者不仅能看懂代码,更能理解其设计哲学。

IT 累计浏览 2,381

Chaos网络库(三)- 主循环及异步消息的实现

这篇讲的是Chaos网络库第三部分,聚焦于其主循环及异步消息机制的实现细节。作者从构建高性能网络库需要解决的核心问题——如何高效处理海量并发连接与消息——出发,深入到了事件驱动模型的具体落地。 文章清晰阐述了主循环作为网络库“心脏”的工作原理:它通常基于epoll(或类似的I/O多路复用机制)不断轮询就绪事件,然后分发给对应的处理器。而更有趣的部分在于异步消息的设计。作者展示了如何通过消息队列与工作线程池配合,将耗时操作(如数据解析、业务逻辑)与I/O事件处理解耦,避免了主循环被阻塞。其中巧妙利用无锁队列或精心设计的锁策略来保证线程安全并提升吞吐量,是一个关键的实现亮点。 这种设计确保了网络库在高负载下仍能保持稳定的响应能力和资源利用率。对于想要了解现代网络框架底层运作,或计划自己设计高并发服务的开发者来说,文章对这两部分协同工作的剖析提供了非常扎实的参考。

IT 累计浏览 2,181

Chaos网络库(二)- Buffer的设计

这篇技术分析聚焦于Chaos网络库中的Buffer模块设计,特别是它如何不同于主流网络库libevent的处理方式。作者直接切入技术细节,指出libevent(以1.4.13版本为例)采用了能自动扩张的传统buffer策略。 而Chaos则另辟蹊径,其buffer设计旨在解决特定场景下的性能与内存管理问题。文章通过对比揭示了两者在内存分配、数据拷贝与扩容机制上的关键差异:libevent偏向灵活通用,Chaos则更注重在已知负载或特定协议下的高效与可控,减少了不必要的内存波动。 这种设计差异直接影响了各自适用的应用场景。对于需要极致性能或资源受限的环境,Chaos的方案可能更具优势;而对于需求多变的一般应用,libevent的经典方式则提供了更大的灵活性。文章通过具体实现思路的剖析,展现了网络库底层设计中权衡与取舍的艺术,为开发者提供了有价值的实现参考。

IT 累计浏览 2,463

TCP/IP源码学习——inet_select_addr函数分析

这篇讲的是Linux内核里TCP/IP协议栈中一个看似不起眼却至关重要的函数——inet_select_addr。作者从源码层面,完整拆解了该函数如何为出站连接挑选源IP地址这一关键决策过程。 文章的核心在于揭示函数内部一套层次分明的选择逻辑。它并非简单取用,而是遵循严格的优先级:首先检查socket是否明确绑定了地址,接着查询路由表获取出口设备对应的地址,最后才考虑回环地址或全局默认地址。这种设计确保了在复杂的多网卡、多地址环境下,数据包总能带上最合适的“发件人”信息,为后续的路由和连接建立打下基础。 文中特别分析了实现的巧妙之处,比如它如何与路由子系统协同工作,以及不同版本(如IPv4与IPv6)内核代码中的差异处理。这种层层递进的决策树,体现了内核在网络配置灵活性与性能之间所做的精巧平衡。对于想深入理解网络栈源码细节、或需要诊断特定网络配置问题的开发者来说,这份对“如何做出正确选择”的源码级剖析,提供了非常清晰的脉络。

IT 累计浏览 2,742

MINA网络通信框架

这篇讲的是 Apache MINA 这个 Java 网络框架,它本质上是为解决传统 NIO 编程中底层细节复杂、容易出错的问题而生的。 作者从网络应用的通用挑战切入:如何高效、可靠地处理海量并发连接。MINA 的核心方案是提供一个基于事件驱动的、分层的异步 I/O 框架,将繁琐的底层操作封装成清晰的组件。文章重点剖析了它的分层架构,比如负责底层传输的 `IoService` 层,以及处理业务逻辑的 `IoHandler` 接口,两者之间还通过 `IoFilterChain` 来进行灵活的数据编解码与拦截处理,这种设计让网络通信的实现变得结构化。 通过这种封装,开发者可以从容应对高并发场景,专注于业务本身。文章最后提到,MINA 广泛应用于即时通讯、游戏服务器等需要长连接和高性能的系统,其简洁的 API 与稳定的性能,使其成为快速构建健壮网络应用的可靠选择。

IT 累计浏览 6,682

浅析linux kernel network之socket创建

作者从Linux内核网络子系统的一个基础但关键的环节——socket对象的创建——出发,梳理了用户空间系统调用到内核数据结构初始化的完整路径。这篇文章并非泛泛而谈,而是聚焦于`sys_socket`入口之后,内核如何通过socket操作集(`proto_ops`)找到对应的协议族(如IPv4),再进一步匹配具体的传输层协议(如TCP)并创建核心的`sock`对象。 其精妙之处在于揭示了这一过程清晰的分层与解耦:从通用的socket层,到特定的协议族层,再到具体的传输层,每一步都通过函数指针表进行动态绑定。作者对`sock`结构体初始化的分析,尤其是协议操作集(`sk_prot`)与socket操作集如何被赋值和关联,让读者能直观理解内核如何为后续的数据收发构建好必要的“骨架”。 对于想了解网络协议栈内部构造的读者,这篇文章提供了一个扎实的起点,它将抽象的“创建连接”动作,拆解成了内核中一系列具体而有序的函数调用与结构体填充,为后续探索数据包的处理流程打下了基础。

IT 累计浏览 2,421

Ring Buffer 的应用

这篇讲的是 Ring Buffer(环形缓冲区)这个经典数据结构的实际应用思考。作者坦言,文章起源于微博上的一场技术讨论甚至争论,他借此机会将散落的观点系统梳理,成文的初衷并非给出一个非黑即白的“最佳方案”,而是为不同技术视角的碰撞提供一个汇总,旨在帮助读者开拓思路。 文章核心探讨了在具体工程场景中采用 Ring Buffer 可能带来的利弊权衡。作者没有停留在教科书式的原理讲解,而是从“信不信这样能更好”的实践角度出发,分析了在特定背景下,Ring Buffer 作为一种解耦、缓冲或同步机制时的适用性。内容涉及了其在高并发、低延迟或流处理等场景中的潜在优势,同时也未回避其可能引入的复杂性或局限性。 如果你在系统设计中曾纠结于选择何种缓冲机制,或者对如何在特定约束下平衡吞吐量与延迟感到困惑,这篇文章提供的正是一次开放式的思路梳理。它更像是一场技术讨论的精华回顾,而非一份标准答案手册,其中关于环形缓冲区线程安全实现与性能权衡的具体讨论,对架构选型和编码实现都有直接的参考价值。

IT 累计浏览 3,242

软件开发的“三重门”

这篇讲的是软件开发中常见但少被系统讨论的“路径选择”问题。作者从“做底层技术还是做业务”这个具体问题出发,回顾了自己十多年的开发经历,将遇到的问题梳理分类,最终沉淀出“三重门”这个思考框架。 文章并非简单比较技术栈的优劣,而是将开发工作解构为三个层面:最内层是解决具体技术难题的“手艺门”,中间是理解商业逻辑与产品交付的“业务门”,最外层则是关于技术视野、团队协作与工程化实践的“工程门”。作者结合实例指出,许多开发者容易困在单一层面,要么执着于炫技而忽视业务价值,要么埋头业务却荒废了技术内功。 这篇内容的价值在于,它不提供一个标准答案,而是为开发者提供了一张“职业地图”。无论你正纠结于技术深度与广度的取舍,还是困惑于个人贡献与团队影响的平衡,文中基于亲身实践的反思与归纳,都能帮助你更清晰地定位自己所处的阶段,理解不同选择背后所需的思维转变与能力积累。

IT 累计浏览 6,123

libevent源码浅析: http库

这篇讲的是开发者常常忽略的 libevent 库内置的 http 模块。作者从如何用最少的代码搭建一个 http 服务器这个实用问题出发,带我们深入其源码。 文章的核心是揭示这个 http 库如何巧妙地建立在 libevent 本身的事件驱动架构之上。分析从初始化一个事件监听器开始,追踪了一个新连接到来后,如何被接管并封装为一个内部事件对象。重点剖析了请求解析、响应生成,以及最关键的——如何将处理逻辑注册为事件回调,从而无缝融入整个事件循环。其中,对连接生命周期和状态机(如等待请求头、等待请求体等)的管理,展示了实现高效、非阻塞网络服务的典型思路。 通过拆解这些实现细节,文章不仅说明了如何使用,更清晰地展现了“事件驱动”与“http 协议处理”相结合的具体编码实践,对理解这类网络库的设计模式很有启发。

IT 累计浏览 3,583

初探Linux网络协议栈

这篇讲的是Linux网络协议栈的核心脉络。作者从数据包的旅程出发,清晰梳理了从网卡接收到应用层处理,再到发送出去的完整路径。文章特别聚焦于内核中几个关键的数据结构,比如 `sk_buff` 如何串联起整个数据包生命周期,以及协议栈各层(如IP、TCP)如何协作处理数据。 它不仅解释了协议栈“是什么”,更深入探讨了“为什么这样设计”。例如,在讨论TCP层时,文章点出了拥塞控制与流控机制如何在内核中被具体实现,并对比了不同拥塞算法(如Reno和Cubic)在处理网络抖动时的策略差异。这种从设计哲学到代码实现的剖析,让抽象的网络概念变得具体可感。 读完后,你不仅能对Linux处理网络数据的流程有宏观认知,更能理解那些高性能服务器调优参数背后的原理——为什么调整某个内核参数会显著影响并发连接数。对于想从“会用”Linux网络迈向“理解”其内核实现的开发者而言,这篇提供了扎实的切入点。