网络编程实战
盛延敏
前大众点评云平台首席架构师
立即订阅
6034 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 学好网络编程,需要掌握哪些核心问题?
免费
第一模块:基础篇 (9讲)
01 | 追古溯源:TCP/IP和Linux是如何改变世界的?
02 | 网络编程模型:认识客户端-服务器网络模型的基本概念
03丨套接字和地址:像电话和电话号码一样理解它们
04 | TCP三次握手:怎么使用套接字格式建立连接?
05 | 使用套接字进行读写:开始交流吧
06 | 嗨,别忘了UDP这个小兄弟
07 | What? 还有本地套接字?
08 | 工欲善其事必先利其器:学会使用各种工具
09丨答疑篇:学习网络编程前,需要准备哪些东西?
第二模块:提高篇 (10讲)
10 | TIME_WAIT:隐藏在细节下的魔鬼
11 | 优雅地关闭还是粗暴地关闭 ?
12 | 连接无效:使用Keep-Alive还是应用心跳来检测?
13 | 小数据包应对之策:理解TCP协议中的动态数据传输
14丨UDP也可以是“已连接”?
15 | 怎么老是出现“地址已经被使用”?
16 | 如何理解TCP的“流”?
17 | TCP并不总是“可靠”的?
18 | 防人之心不可无:检查数据的有效性
19丨提高篇答疑:如何理解TCP四次挥手?
期中复习周 (2讲)
期中大作业丨动手编写一个自己的程序吧!
免费
期中大作业丨题目以及解答剖析
免费
第三模块:性能篇 (12讲)
20 | 大名⿍⿍的select:看我如何同时感知多个I/O事件
21 | poll:另一种I/O多路复用
22 | 非阻塞I/O:提升性能的加速器
23 | Linux利器:epoll的前世今生
24 | C10K问题:高并发模型设计
25 | 使用阻塞I/O和进程模型:最传统的方式
26 | 使用阻塞I/O和线程模型:换一种轻量的方式
27 | I/O多路复用遇上线程:使用poll单线程处理所有I/O事件
28 | I/O多路复用进阶:子线程使用poll处理连接I/O事件
29 | 渐入佳境:使用epoll和多线程模型
30 | 真正的大杀器:异步I/O探索
31丨性能篇答疑:epoll源码深度剖析
第四模块:实战篇 (4讲)
32 | 自己动手写高性能HTTP服务器(一):设计和思路
33 | 自己动手写高性能HTTP服务器(二):I/O模型和多线程模型实现
34 | 自己动手写高性能HTTP服务器(三):TCP字节流处理和HTTP协议实现
35 | 答疑:编写高性能网络编程框架时,都需要注意哪些问题?
结束语 (1讲)
结束语丨我相信这不是结束,让我们江湖再见
网络编程实战
登录|注册

07 | What? 还有本地套接字?

盛延敏 2019-08-16
你好,我是盛延敏,这里是网络编程实战第 7 讲,欢迎回来。
上一篇文章中,我们讲了 UDP。很多同学都知道 TCP 和 UDP,但是对本地套接字却不甚了解。
实际上,本地套接字是 IPC,也就是本地进程间通信的一种实现方式。除了本地套接字以外,其它技术,诸如管道、共享消息队列等也是进程间通信的常用方法,但因为本地套接字开发便捷,接受度高,所以普遍适用于在同一台主机上进程间通信的各种场景。
那么今天我们就来学习下本地套接字方面的知识,并且利用本地套接字完成可靠字节流和数据报两种协议。

从例子开始

现在最火的云计算技术是什么?无疑是 Kubernetes 和 Docker。在 Kubernetes 和 Docker 的技术体系中,有很多优秀的设计,比如 Kubernetes 的 CRI(Container Runtime Interface),其思想是将 Kubernetes 的主要逻辑和 Container Runtime 的实现解耦。
我们可以通过 netstat 命令查看 Linux 系统内的本地套接字状况,下面这张图列出了路径为 /var/run/dockershim.socket 的 stream 类型的本地套接字,可以清楚地看到开启这个套接字的进程为 kubelet。kubelet 是 Kubernetes 的一个组件,这个组件负责将控制器和调度器的命令转化为单机上的容器实例。为了实现和容器运行时的解耦,kubelet 设计了基于本地套接字的客户端 - 服务器 GRPC 调用。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《网络编程实战》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(37)

  • Sylar.
    老师您好,方便把全部代码放git吗,因为示例缺少依赖

    作者回复: 答疑篇统一回复

    2019-08-17
    5
  • supermouse
    问题一:连接不上。错误提示是“Permission denied”

    问题二:在服务端的代码中,对收到的客户端发送的数据长度做了判断,如果长度为0,则主动关闭服务端程序。这是杀死客户端后引发服务端关闭的原因。这也说明客户端在被强行终止的时候,会最后向服务端发送一条空消息,告知服务器自己这边的程序关闭了。

    问题三:客户端在连接时会报错,错误提示是“Protocol wrong type for socket (91)”

    作者回复: 看样子你都尝试了,实践出真知,赞

    2019-11-03
    1
    4
  • 许童童
    1.没有权限,报permission deny错误。
    2.代码中有写:
    if (read(connfd, buf, BUFFER_SIZE) == 0) {
                printf("client quit");
                break;
            }
    3.客户端使用的是 SOCK_STREAM。猜测会因为使用协议不同,会连接不上,报错。
    2019-08-16
    1
    4
  • yusuf
    1、不能连接,需要权限才能对sock文件进行读写
    2、代码30~33行,服务器读到的数据长度为0时会退出。
    3、认为会出现如下现象:
    如果服务器写错了,服务器会输出listen failed,客户端会输出connect failed;
    如果客户端写错了,服务器会输出client quit,客户端会输出sendto error。
    2019-08-16
    2
    3
  • 刘丹
    请问老师本地套接字是否支持一对多、多对多通信?

    作者回复: 本地套接字datagram就可以

    2019-08-16
    1
    3
  • 刘晓林
    datagram client中,为什么还要bind一个本地地址呀?没有看出这个这个本地地址有什么用呀。难道它是用来作为接受数据的缓冲区的吗?好像没有它也并不影响数据收发,换句话说,client_addr.sun_path填什么好像都无所谓啊。

    作者回复: 这个值是为了回包的需要,常规情况是不需要的,但是在某些情况下还是有点作用的,比如让客户端快速出错。

    2019-08-30
    2
  • GeekAmI
    问题1:
    $ sudo ./unixstreamserver /var/lib/unixstream.sock

    $ ./unixstreamclient /var/lib/unixstream.sock
    connect failed: Permission denied (13)

    问题2:
    client: Ctrl + C -> exit(0) -> 发送FIN包;
    server:满足条件read(connfd, buf, BUFFER_SIZE) == 0,结束。

    问题3:
    $ ./unixdataserver /tmp/unixdata.sock

    $ ./unixstreamclient /tmp/unixdata.sock
    connect failed: Protocol wrong type for socket (41)

    作者回复: 👍

    2019-10-17
    1
  • 15652790052
    1.sock文件具体内容什么呢,为什么需要sock文件?
    2.本地套接字底层时怎么实现的呢?
    3.为什么没有了端口的概念?

    作者回复: 1.没什么内容,只是一个占位符,告诉客户端要连哪个sock;
    2.没有仔细研读过kernel的代码,不过我猜是大量复用了TCP/IP层的公共实现;
    3.因为文件已经告诉我们连接的目标了,所以不需要端口。

    2019-08-29
    1
  • knull
    老师,你好,我练习写了一个echoserver(用AF_UNIX),客户端主动断链。
    发现在客户端close的时候,echoserver会读取到数据,并且最后一次write。但是,这个时候连接已经断了,会报错broken pipe。程序直接挂掉了。。。
    这种情况该怎么处理呢?

    作者回复: 1.加一个SIGPIPE信号处理
    2.读到EOF就不要write了

    2019-08-26
    1
    1
  • 沉淀的梦想
    请问一下如何能方便地知道一个linux系统提供的函数或者变量的头文件是哪个呢?经常不知道文中的代码的函数或者变量的头文件在哪里

    作者回复: 你可以在linux系统里执行man命令,例如man socket:

    SOCKET(2) Linux Programmer's Manual SOCKET(2)

    NAME
           socket - create an endpoint for communication

    SYNOPSIS
           #include <sys/types.h> /* See NOTES */
           #include <sys/socket.h>

           int socket(int domain, int type, int protocol);

    2019-08-17
    1
    1
  • 一步
    文章中说 TCP 和 UDP 的scoket 通讯 是走网络协议的,本地socket 通讯减少了网络协议的实现,是说明本地scoket通讯一点都不走网络协议吗? 还是会走其中的一部分网络协议?

    如果本地 socket 通讯不走网络协议,那通讯的标准是什么呢? 只是对 socket 文件的读写操作吗?

    作者回复: 我是这么理解的,本地套接字本质还是进程间通信,只是借助了套接字的编程语义,比如stream和datagram,最下面肯定不走IP协议的。

    2019-08-17
    1
  • HunterYuan
    对于第二个问题,第五讲已进行了充分说明:read 函数要求操作系统内核从套接字描述字 socketfd读取最多多少个字节(size),并将结果存储到 buffer 中。返回值告诉我们实际读取的字节数目,也有一些特殊情况,如果返回值为 0,表示 EOF(end-of-file),这在网络中表示对端发送了 FIN 包,要处理断连的情况。
    也就是说,只有流方式会遇到这种情况:
    client: Ctrl + C -> exit(0) -> 发送FIN包;
    server:满足条件read(connfd, buf, BUFFER_SIZE) == 0,结束。

    作者回复: 头像好赞。

    2019-11-28
  • godtrue
    本地套接字是一种特殊类型的套接字,和 TCP/UDP 套接字不同。TCP/UDP 即使在本地地址通信,也要走系统网络协议栈,而本地套接字,严格意义上说提供了一种单主机跨进程间调用的手段,减少了协议栈实现的复杂度,效率比 TCP/UDP 套接字都要高许多。类似的 IPC 机制还有 UNIX 管道、共享内存和 RPC 调用等。
    这里的描述,“减少了协议栈实现的复杂度”,没理解本地套接字,具体还走不走网络的协议栈?如果走应该仍然属于网络通信的范畴,如果不走,他具体怎么实现的,和共享内存有什么本质区别?
    这里确实刷新了认知,之前认为进程间通信,必须要走网络协议的,哪怕是单机上的两个进程也是这样。其实只要他们能交流信息,走不走网络没什么必然联系,共享内存这个就容易理解和实现,不过还是需要约定双方交流的方式,否则信息能获取但不理解也不成。
    2019-11-22
  • Geek_d4f974
    运行server后,在netstat -lx中可以查看到,但是在/tmp文件夹中没有生成unixstream.sock文件

    作者回复: 不会啊,会不会是权限的问题?你是root账号么?

    2019-10-08
  • 曹绍坚
    "另外还要明确一点,这个本地文件,必须是一个“文件”,不能是一个"目录";"
    这么说本地套接字是不是不适合实现多并发的服务器?

    作者回复: 没有这么说,目录-文件这个和并发有关系么?

    2019-09-24
  • Kepler
    lib/common.h 的绝对路径是啥,有这个文件吗?

    作者回复: https://github.com/froghui/yolanda/blob/master/lib/common.h

    2019-09-22
  • 岸超
    1:普通用户应该是没有 /var/lib/unixstream.sock 这个文件的读写权限的,root创建一般会是700的形式。可以手动chmod添加权限,使得普通用户也可以访问该本地套接字。
    2:这个问题在 流式套接字和数据报两种情况应该是不同的吧。流式套接字中应该是复用了socket close的语义,进程退出会关闭fd,而对端的read在tcp连接时,收到fin分节会返回0,这里在本地套接字上应该是模拟了对端close时的这种效果。但是数据报套接字是不存在这种情况下返回0的实现的,故而这段代码其实不会生效,实际效果展示中也没有退出
    3:问题三肯定会报错,虽不会三次握手,但内核肯定无法把这两种套接字在底层连接起来,但具体错误未知。
    2019-09-13
  • Geek_Wison
    老师您好,这篇文章的第一段代码的第33~36行的if else是不是写得不太对?

    作者回复: C语言可以接收这样不带花括号的简单写法。

    2019-09-06
    1
  • knull
    老师,能不能说说两种unix套接字的使用场景?tcp和udp有明显的特征差异。但是,unix的好像差别不是特别明显。我想象中,本地的话,丢包可能基本没有吧?仅仅是为了与tcp、udp对应,还是有特别的意义?

    作者回复: 我理解是编程模型的差别

    2019-08-27
    1
  • fee
    计算地址长度 len = offset(struct sockaddr_un, sun_family) + strlen(.sun_family)公司代码

    作者回复: 可以的,通过指针位置来计算offset,再补上协议本身的大小。

    2019-08-20
收起评论
37
返回
顶部