36|打稳根基:怎么实现一个TCP服务器?(上)
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
本文深入介绍了TCP服务器的实现技术,以Go语言为例,详细讲解了网络编程的概念、TCP/IP网络模型、TCP和UDP协议的特点和应用场景。重点讨论了阻塞I/O、非阻塞I/O和I/O多路复用等网络I/O模型,并解释了Go语言采用的阻塞I/O模型及其实现原理。此外,还介绍了socket监听与接收连接的核心套路,以及服务端程序的处理流程。文章还涵盖了向服务端建立TCP连接、全双工通信和Socket读操作等内容。通过具体例子和代码展示了TCP服务器实现中的阻塞、部分数据写入和超时等特殊情况,为读者呈现了实际应用中的挑战和解决方案。同时,还提到了多Goroutine并发读写Socket的情况,为读者展示了更加复杂的应用场景。整体而言,本文内容丰富,适合对TCP服务器实现技术感兴趣的读者深入学习和实践。文章内容详实,通过具体例子和代码展示了TCP服务器实现中的阻塞、部分数据写入和超时等特殊情况,为读者呈现了实际应用中的挑战和解决方案。
《Tony Bai · Go 语言第一课》,新⼈⾸单¥59
全部留言(20)
- 最新
- 精选
- 在下宝龙、老师我想问一下 按照老师你的图,select不是也阻塞了线程么,应用线程也不能做其他的事情,难道应用线程和select的线程不是同一个吗
作者回复: io多路复用顾名思义,一个线程可以处理多个socket,只要有一个socket上可读或可写,线程就会忙碌起来。当然如果所有socket都不可读,也不可写,那么该线程的确是处理阻塞状态。但这和一个线程仅能处理一个socket,还阻塞在该socket的读/写上相比,是有质的飞跃的。
2022-01-245 - bearlu老师,有没有netpoller的相关实现资料参考?
作者回复: 我最初是看了这篇文章 https://morsmachine.dk/netpoller ,之后自己read source code的。只有自己读代码,结果才深刻。
2022-01-245 - 撕影由于go的GPM模型存在,实现多路复用简直就是降维打击。只挂起G而不挂起M,在G的视角里就是个阻塞模型而已,妙啊
作者回复: 👍
2022-11-30归属地:辽宁4 - Aeins读完,好多细节还抓不住 1. go 中的 Socket 是操作系统 socket 的封装。go 通过 netpoller 模拟了阻塞式的I/O,运行时还是使用的I/O多路复用(不同操作系统提供了不同的系统调用,epoll等) 连接复用的情况 0. 读写都有锁保护 1. 多 goroutine 并发读,如何正确的指定度多少数据呢,给少了,会读不全,被其他 goroutine 读走,给多了,会读取不属于自己的数据吧。 2. 多 goroutine 并发写,如果一次写入一个完整的”业务包“,一般能保证单个业务包的完整 ,如果写超时,会有部分写入问题吗? 一次写入一个业务包,TCP会从面向数据流,退化到面向业务包码? 读的一端,为了区分不同goroutine(共用连接,数据不共享)的数据,要采取特殊的读取方式吗,需要以包为单位读取?
作者回复: 这里仅是介绍了并发下网络I/O的可能存在的极端情况。实际设计中,尽量避免对一个socket的并发读和并发写。
2022-06-063 - bearlu谢谢老师。我跟上了。还特意买了你新出的Go语言精进之路1,2,打算过年继续精进。
作者回复: 👍。
2022-01-2433 - Mew151本节课的代码参见:https://github.com/dgqypl/tcpprogramming
作者回复: 👍
2022-10-10归属地:辽宁22 - 一打七老师,有个地方想不清楚,请教一下。现在都是长连接复用一个tcp连接,这时服务端读取一个请求的部分数据后异常了,还有一部分数据未读取,这时下一个请求过来了,服务端应该怎么处理上一个请求遗留的那部分数据?因为tcp层面是没有业务语义的,怎么区分这部分数据要不要丢弃。
作者回复: tcp仅是传输层协议。如何识别应用层协议包的是应用层协议来规定的。 像你提到的,如果某个应用层请求包存在数据异常,如果异常会导致后续所有请求均处理失败,那么意味着这个连接存在的意义不大了,断连是最好的选择。后续的请求由于没有得到服务端的应答,所以client端应该选择重发。 如果数据异常的请求对后续新请求没有太大影响,服务端可以选择将请求的剩余数据读取后,回复特定的失败应答。然后继续读取和处理后续的新请求。
2022-07-062 - lesserror以前没接触过socket编程,只是经常看到这个知识点。感谢Tony Bai老师的细致讲解。有几点疑惑,烦请老师解答。 1. 我们的输入,是一个基于传输层自定义的应用层协议规范。 这里的输入该怎么理解呢? 2. 在阻塞 I/O 模型下,并等所有数据就绪后,将数据从内核空间拷贝到用户空间,最后系统调用从内核空间返回。为什么不是用户空间返回呢? 3. 文中的非阻塞 I/O 模型架构图中的:EAGAIN/EWOULDBLOCK 这几个英文单词是什么意思,没查出来。
作者回复: 很高兴又看到lesserror回来学习了! 我来说说你提出的问题。 1. 输入:指的是我们要实现的tcp服务器的输入,就是服务器要接收的数据。这些数据符合某种应用层协议的规范。 2. 系统调用后,线程便进入内核空间执行了,即进入内核态。在内核态的系统调用代码将获得的数据从内核层的缓存中copy到用户层的内存中,执行结束后,从内核态返回用户态。用户便可以在用户层的内存中看到已经返回的数据了。可以参考一下《深入理解计算机系统3rd》这本书对计算机整体做了一个全面深入了解。 3. EAGAIN/EWOULDBLOCK 是两个系统级的错误。E是前缀,以EAGAIN为例,即Error Again,即告知调用者重试。
2022-02-172 - Calvin老师,文章中“I/O 多路复用框架”的举例中: 1、libev 的链接点击没反应(是 http://software.schmorp.de/pkg/libev.html 这个链接吗?); 2、libuv 的链接对应的 github 仓库貌似已经迁移到 https://github.com/libuv/libuv 了。
作者回复: 1. 是的,文中链接好像多了一个空格,导致无效了。 2. 确实。感谢提醒。我让编辑老师改一下。
2022-01-2622 - 罗杰并发往 socket 中写数据时,需要一次 write 操作完整的写入一个“业务包”,这实现有点难呀,万一只成功写入一部分,这可不能回滚呀。
作者回复: 你的业务场景中有并发写一个conn的情况么?
2022-01-2432