作为一个Web开发程序员,我每天都在和HTTP、TCP/IP打交道。
但是说实话,之前我对网络编程的理解很肤浅,只知道发请求、收响应,底层是怎么回事完全不清楚。遇到连接超时、端口被占用、TIME_WAIT过多这些问题,只能瞎猜,或者Google一下,复制粘贴解决方案,根本不知道为什么。
直到去年,我花了几个月时间系统地学习了TCP/IP网络编程,才终于搞懂了很多之前困惑的问题,排查网络相关的问题也不再瞎猜了。
今天就来分享一下我的TCP/IP网络编程学习路线,聊聊我是怎么入门的,希望能对想学习网络编程的朋友有所帮助。
一、为什么要学网络编程
先说说为什么要花时间学网络编程。
很多人可能会说,我是做Web开发的,框架都封装好了,我只要调用API就行了,为什么要学底层的网络编程?
我之前也是这么想的,但是后来遇到了几个问题,让我意识到不学不行:
1. 排查问题需要
有一次线上出了个问题,服务偶尔连接超时,重启就好,但是过一段时间又出现。我查了半天代码,没发现问题,后来还是一个运维同事帮我查的,说是TCP连接的TIME_WAIT状态过多,导致端口耗尽,调整了内核参数就好了。
那时候我连TIME_WAIT是什么都不知道,更别说怎么排查了。这件事让我意识到,不懂网络编程,遇到网络相关的问题就是瞎子摸象,根本没法排查。
2. 理解框架原理需要
我们用的Web框架、RPC框架、数据库连接池,底层都是基于Socket的。不懂网络编程,就只能停留在调用API的层面,没法深入理解框架的原理,遇到框架的性能问题或者诡异bug,就没法解决。
比如Nginx为什么高性能?Netty为什么快?数据库连接池为什么要这么设计?这些问题的答案都在网络编程里。
3. 职业发展需要
如果想从普通开发进阶到高级开发、架构师,网络编程是绕不开的基本功。分布式系统、微服务、高性能服务,这些都离不开网络编程。不懂网络编程,职业发展会遇到瓶颈。
而且,网络编程是计算机科学的基础之一,和操作系统、数据库、数据结构一样,是程序员的基本功,不管你做什么方向,都应该了解。
二、基础知识储备
在正式学习网络编程之前,需要有一些基础知识储备:
1. 操作系统基础
网络编程和操作系统紧密相关,Socket是操作系统提供的接口,I/O模型、进程线程、信号等概念都需要了解。
不需要深入到内核级别,但是至少要知道进程和线程的区别、什么是阻塞和非阻塞、什么是同步和异步、I/O模型有哪几种。
推荐先看一下《操作系统导论》或者B站上的操作系统公开课,有个基本概念就行。
2. C语言基础
Socket API最早是C语言的,很多经典的网络编程书籍都是用C语言写的。所以需要有一点C语言基础,能看懂C代码就行,不需要精通。
如果完全不会C语言,建议先看一下《C语言入门经典》或者类似的入门书,花一两周时间了解基本语法,能看懂代码就行。
当然,现在也有很多用Python、Java讲网络编程的书,但是经典的还是C语言的,建议还是学点C基础。
3. 计算机网络基础
需要了解计算机网络的基本概念,比如OSI七层模型、TCP/IP四层模型、IP地址、端口、TCP和UDP的区别等。
这些是网络编程的基础,不知道这些,学Socket编程会很懵。
推荐先看一下《计算机网络:自顶向下方法》的前几章,或者B站上的计算机网络公开课,有个基本概念。
三、推荐书籍
有了基础知识之后,就可以开始正式学习网络编程了。推荐几本书:
1. 《TCP/IP详解 卷1:协议》
这是网络编程的圣经,必读书籍。这本书详细讲解了TCP/IP协议族的各个协议,包括IP、ICMP、TCP、UDP、DNS、HTTP等,讲得非常透彻。
这本书比较厚,也比较难读,建议不要一口气读完,可以先读前几章(IP、TCP),有个基本概念,然后边学Socket编程边回头看对应的章节,这样效果更好。
2. 《UNIX网络编程 卷1:套接字联网API》
这是Socket编程的经典书籍,详细讲解了Socket API的各种用法,包括TCP、UDP、I/O多路复用、并发服务器等。
这本书也是大部头,但是写得很详细,代码示例很多,适合边看边写代码。建议重点看TCP套接字、I/O多路复用(select/poll/epoll)、并发服务器这几章。
3. 《高性能MySQL》(网络相关章节)
虽然这是数据库的书,但是里面有几章讲MySQL的网络通信和连接管理,对理解网络编程在实际项目中的应用很有帮助。
4. 《Linux高性能服务器编程》
这本书是国内作者写的,比较贴合实际,讲解了Linux下高性能服务器编程的各个方面,包括TCP/IP、Socket、I/O模型、进程线程、信号、定时器等,还有一个完整的服务器项目实战。
这本书相对薄一些,也更容易读,适合作为入门之后的进阶读物。
四、学习路线
我自己的学习路线大概是这样的,分四个阶段:
第一阶段:基础概念(2周)
先花两周时间,把计算机网络和操作系统的基础概念过一遍,重点搞清楚:
- OSI七层模型和TCP/IP四层模型
- IP地址、子网、端口
- TCP和UDP的区别
- TCP三次握手、四次挥手
- 阻塞/非阻塞、同步/异步
- 进程和线程
不需要深入,有个基本概念就行,知道每个东西大概是干什么的。
第二阶段:Socket基础编程(4周)
然后花四周时间,学习基础的Socket编程,跟着书写代码:
- 先写一个最简单的TCP回显服务器和客户端,服务端接收客户端发的消息,原样返回。
- 然后写一个多进程/多线程的并发服务器,能同时处理多个客户端。
- 再学习UDP编程,写一个UDP的回显服务器和客户端。
- 学习I/O多路复用,用select/poll/epoll重写并发服务器。
- 学习一些高级功能,比如超时处理、信号处理、地址复用等。
这个阶段的重点是动手写代码,不要只看书不写。每学一个知识点,就写一个小demo,跑起来,调试一下,理解原理。
第三阶段:协议和原理(4周)
有了Socket编程的基础之后,再回头深入学习TCP/IP协议的原理:
- 重点看TCP协议,包括三次握手、四次挥手、流量控制、拥塞控制、超时重传等。
- 看IP协议,包括分片、路由、ICMP等。
- 看应用层协议,比如HTTP、DNS、FTP等,理解应用层协议是怎么基于TCP/UDP实现的。
- 用Wireshark抓包分析,实际看看TCP三次握手、四次挥手的包长什么样,HTTP请求响应的包是什么样的。
这个阶段的重点是理解原理,结合抓包工具,把理论和实际对应起来。
第四阶段:项目实战(持续)
最后就是项目实战,把学到的知识用到实际项目中:
- 可以自己写一个简单的HTTP服务器,支持静态文件、GET/POST请求,理解Web服务器的原理。
- 可以写一个简单的RPC框架,理解远程调用的原理。
- 可以研究一下Nginx、Redis、Netty等开源项目的网络部分,看看高性能服务器是怎么实现的。
- 在工作中遇到网络相关的问题,尝试用学到的知识去分析和解决。
这个阶段是持续的,在实际项目中不断加深理解。
五、动手实践很重要
学习网络编程,动手实践特别重要,不能只看书不写代码。
我自己的体会是,很多概念看书的时候觉得懂了,但是一写代码就发现根本没懂。比如TCP的粘包问题,看书的时候觉得很简单,但是自己写代码的时候,才发现要处理好粘包和分包并不容易,需要设计应用层协议。
还有I/O多路复用,看书的时候觉得select/poll/epoll的区别很清楚,但是自己写代码的时候,才发现epoll的ET模式和LT模式有很多坑,处理不好就会丢事件。
所以一定要动手写代码,每学一个知识点,就写一个小demo,跑起来,调试一下,遇到问题再回头看书,这样理解才深刻。
另外,抓包工具也很重要。推荐用Wireshark,学习TCP的时候,自己写个客户端和服务端通信,然后用Wireshark抓包,看看三次握手、四次挥手、数据传输的包实际是什么样的,这样对协议的理解会非常深刻。
还有一些命令行工具也很有用,比如netstat、ss、lsof、tcpdump等,排查网络问题的时候经常用到,建议熟悉一下。
六、常见的坑
学习网络编程的过程中,我踩了不少坑,分享几个常见的:
1. TCP粘包问题
TCP是面向流的协议,没有消息边界,所以会有粘包问题。很多新手一开始不知道这个,写的代码偶尔能收到完整消息,偶尔收到半截消息,调试半天找不到原因。
解决方法是在应用层设计协议,比如固定长度、用分隔符、或者在消息头里加长度字段,接收方根据协议来拆分消息。
2. 端口被占用
服务器重启的时候,经常遇到"Address already in use"的错误,这是因为之前的连接还在TIME_WAIT状态,端口还没释放。
解决方法是设置SO_REUSEADDR选项,允许地址复用,这样重启的时候就不会报错了。
3. 大端小端问题
网络字节序是大端的,而x86主机是小端的,所以传输多字节数据的时候需要用htonl/htons/ntohl/ntohs等函数转换字节序,否则会出问题。
很多新手不知道这个,传输int类型的数据,对端收到的是乱码,调试半天找不到原因。
4. 阻塞和非阻塞的区别
阻塞模式下,accept、recv、send等函数会阻塞等待,非阻塞模式下会立即返回。很多新手对这个概念不清楚,写的代码要么阻塞住没法处理其他连接,要么非阻塞模式下没处理好EAGAIN错误。
建议先理解阻塞和非阻塞的区别,然后分别写阻塞和非阻塞的版本,对比一下,理解会更深刻。
5. epoll的ET模式坑
epoll的ET(边缘触发)模式性能更高,但是坑也多。ET模式下,只有状态变化的时候才会触发事件,所以读数据的时候必须一次性读完,直到recv返回EAGAIN,否则下次不会再触发读事件,数据就丢了。
很多新手用ET模式,没读完数据就返回,结果发现后续的消息收不到了,调试半天找不到原因。建议新手先用LT(水平触发)模式,熟悉了之后再用ET模式。
七、进阶方向
入门之后,还有很多进阶方向可以深入:
1. 高性能服务器编程
学习Reactor模式、Proactor模式、事件驱动、零拷贝、内存池等高性能服务器技术,研究Nginx、Redis、Netty等开源项目的实现。
2. 协议设计
学习如何设计应用层协议,比如protobuf、thrift、http2等,理解协议设计的 trade-off。
3. 网络安全
学习SSL/TLS、加密、认证、防火墙、DDoS防护等网络安全知识。
4. 内核网络栈
深入Linux内核,学习内核网络栈的实现,比如TCP协议在kernel里是怎么实现的,调优内核网络参数。
5. 分布式系统
网络编程是分布式系统的基础,进阶可以学习分布式系统、一致性协议、RPC框架等。
八、写在最后
TCP/IP网络编程学习路线:我是怎么入门的。
网络编程是程序员的基本功,不管你做什么方向,都应该了解一下。它不仅能帮你排查很多诡异的网络问题,也能让你对计算机系统有更深入的理解,对职业发展很有帮助。
学习网络编程没有捷径,就是看书+写代码+抓包+实践,一步一步来。不要被厚厚的经典书吓到,也不要觉得底层知识没用,等你遇到问题的时候,就会知道这些知识有多重要了。
我自己花了几个月时间入门,现在还在不断学习和实践中,感觉越学越觉得自己懂得少,网络编程的水很深,需要持续学习。
希望这篇文章能对想学习网络编程的朋友有所帮助。如果有什么问题,欢迎在评论区交流,大家一起学习进步。
最后,用一句话结尾:
"基础不牢,地动山摇。网络编程是程序员的基础,花点时间学好,终身受益。"
愿大家都能打好基础,成为更优秀的程序员。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录