Tony Bai · Go 语言第一课
Tony Bai
资深架构师,tonybai.com 博主
21492 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 59 讲
开篇词 (1讲)
结束语 (1讲)
Tony Bai · Go 语言第一课
15
15
1.0x
00:00/00:00
登录|注册

36|打稳根基:怎么实现一个TCP服务器?(上)

写入超时
写入部分数据
写阻塞
读操作超时
足够数据读取
部分数据读取
无数据阻塞
发送缓冲区和接收缓冲区
net.DialTimeout
net.Dial
Goroutine与netpoller
阻塞I/O模型
传输层协议:TCP和UDP
实现基于TCP的自定义应用层协议通信服务端
设计、实现与优化
技术预研与储备
理解问题
准备下一讲的设计与实现
编写代码实践Socket编程
服务端Read返回io.EOF
客户端主动关闭
读写操作的串行化
Goroutine并发安全
Socket写操作
Socket读操作
全双工通信
向服务端建立TCP连接
socket监听(listen)与接收连接(accept)
Go语言socket编程模型
I/O多路复用(I/O Multiplexing)
非阻塞I/O(Non-Blocking I/O)
阻塞I/O(Blocking I/O)
套接字(socket)编程
TCP/IP四层模型
OSI七层模型
实际问题
最后一公里
思考题
Socket关闭
并发Socket读写
Socket读写操作
Go语言网络I/O操作
TCP Socket编程模型
网络编程
实战篇
打稳根基:怎么实现一个TCP服务器?

该思维导图由 AI 生成,仅供参考

你好,我是 Tony Bai。欢迎来到这门课的最后一个部分:实战篇。
在进入正文之前,我先来说点题外话。去年我读过一本名为《陪孩子走过初中三年》的书,书中作者女儿的初中班主任有一句“名言”:“跟上了!”作者对这句名言的解读是:学习上,她强调孩子们学习的时候不要掉队,意思是一要跟上老师的步子,上课认真听讲,课后老师留的作业要不打折扣地去完成;二也要跟上年级和班级的进度。只要能紧紧地跟上,学习就不会有太大的问题。
在前面课程的留言区,我也经常用“跟上了”作为学习这门课的建议,和我一起同步走到这里的同学,都是践行“跟上了”这句“名言”的典范,从开篇词到现在,你是不是已经感受到了自己在 Go 语言方面的进步了呢?
好了,我们言归正传。关于最后一篇写啥,我也想了许久。开篇词中提过,实战篇的职责是带着你走完 Go 语言学习的“最后一公里”,那究竟什么是“最后一公里呢?该如何理解这最后一公里呢?
我的理解是,在掌握了前面的 Go 语言语法的前提下,这“最后一公里”就是面对一个实际问题的解决思路。很多语言初学者都有这样一个问题,即便学完了语法,面对一个实际问题时,还是也不知道该从何处着手。
其实这个事并没有那么难,尤其是程序员这一行,遇到一个实际问题,我们通常使用这个思路:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
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-24
    5
  • bearlu
    老师,有没有netpoller的相关实现资料参考?

    作者回复: 我最初是看了这篇文章 https://morsmachine.dk/netpoller ,之后自己read source code的。只有自己读代码,结果才深刻。

    2022-01-24
    5
  • 撕影
    由于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-06
    3
  • bearlu
    谢谢老师。我跟上了。还特意买了你新出的Go语言精进之路1,2,打算过年继续精进。

    作者回复: 👍。

    2022-01-24
    3
    3
  • Mew151
    本节课的代码参见:https://github.com/dgqypl/tcpprogramming

    作者回复: 👍

    2022-10-10归属地:辽宁
    2
    2
  • 一打七
    老师,有个地方想不清楚,请教一下。现在都是长连接复用一个tcp连接,这时服务端读取一个请求的部分数据后异常了,还有一部分数据未读取,这时下一个请求过来了,服务端应该怎么处理上一个请求遗留的那部分数据?因为tcp层面是没有业务语义的,怎么区分这部分数据要不要丢弃。

    作者回复: tcp仅是传输层协议。如何识别应用层协议包的是应用层协议来规定的。 像你提到的,如果某个应用层请求包存在数据异常,如果异常会导致后续所有请求均处理失败,那么意味着这个连接存在的意义不大了,断连是最好的选择。后续的请求由于没有得到服务端的应答,所以client端应该选择重发。 如果数据异常的请求对后续新请求没有太大影响,服务端可以选择将请求的剩余数据读取后,回复特定的失败应答。然后继续读取和处理后续的新请求。

    2022-07-06
    2
  • 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-17
    2
  • Calvin
    老师,文章中“I/O 多路复用框架”的举例中: 1、libev 的链接点击没反应(是 http://software.schmorp.de/pkg/libev.html 这个链接吗?); 2、libuv 的链接对应的 github 仓库貌似已经迁移到 https://github.com/libuv/libuv 了。

    作者回复: 1. 是的,文中链接好像多了一个空格,导致无效了。 2. 确实。感谢提醒。我让编辑老师改一下。

    2022-01-26
    2
    2
  • 罗杰
    并发往 socket 中写数据时,需要一次 write 操作完整的写入一个“业务包”,这实现有点难呀,万一只成功写入一部分,这可不能回滚呀。

    作者回复: 你的业务场景中有并发写一个conn的情况么?

    2022-01-24
    3
    2
收起评论
显示
设置
留言
20
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部