网络编程学习6--本地套接字

820 阅读6分钟

本地socket是IPC(Inter-Process Communication,进程间通信),也就是本地进程间通信的一种方式。除了本地socket以外,管道、共享消息队列也是进程间通信的常用方法。本地socket普遍适用于在同一台主机上的进程间通信的各种场景。

本地socket

本地套接字一般也叫做UNIX域套接字,它是一种特殊类型的套接字。TCP/UDP套接字即使在本地地址通信,也要走系统网络协议栈,而本地socket提供了一种单主机跨进程间调用的手段,减少了协议栈实现的复杂度,效率比 TCP/UDP 套接字都要高许多。类似的IPC 机制还有 UNIX 管道、共享内存和 RPC 调用等。

RPC

RPC的意思是远程过程调用,是一个计算机通信协议,处于网络通信协议的第五层:会话层,其下是TCP/IP协议。它是一种通过网络从远程计算机上请求服务,而不需要了解底层网络技术的协议。

过程是什么? 过程就是业务处理、计算任务,更直白的说,就是程序,就是想调用本地方法一样调用远程的过程

RPC的出现主要是为了解决分布式系统间的通信透明性问题。

什么是分布式系统间的通信透明性问题?
举个例子,比如说此时需要查看一个订单详情,然后订单系统部署了三台机器。假设没有RPC,其它系统想通过调用订单系统查询订单详情的信息,就必须知道订单系统部署机器的ip和端口,每个调用者必须关注订单系统新加或者下线和换机器部署等情景。所以,分布式系统通信就应该是透明的,这样调用者就不需要关心调用的是哪台机器上面的服务。在调用者的角度这个远程服务应该和调用本地服务一样是一个单一稳定可靠的服务

基于这样的背景有人就提出了一种与传统方法截然不同的通信手段:不同机器上的进程是允许相互调用的,当机器A上的进程调用机器B上的进程时,A上的调用进程被挂起,而B上的被调用进程开始执行。调用方可以通过使用参数将信息传送给被调用方,然后可以通过传回的结果得到信息。编程人员看不到任何消息传递过程。这个方法就被称为远程过程调用RPC.

RPC的调用过程如下:

RPC调用.png

  1. 调用者以本地调用的方式发起调用
  2. 客户端存根(client stub)收到调用后,负责将被调用的方法名、参数等打包编码成特定格式的能进行网络传输的消息体
  3. client stub 将消息体通过网络发送给服务端
  4. 服务端存根(server stub)通过网络接收到消息后按照相应格式进行拆包解码,获取方法名和参数
  5. server stub 根据方法名和参数进行本地调用
  6. 被调用者在本地调用执行后,将调用结果返回给server stub
  7. server stub将结果打包编码成消息体,并通过网络发送给对端
  8. client stub收到消息后,进行拆包解码,并将结果返回给调用者
  9. 调用者得到本次RPC调用的最终结果

RPC与传统HTTP协议对比

优点:

  1. 传输效率高(二进制传输)
  2. 发起调用的一方无需知道RPC的具体实现,就如调用本地函数般调用 缺点:
    通用性不如HTTP好(HTTP是标准协议)

综上,RPC适合内部服务间的通信调用;HTTP适合面向用户与服务间的通信调用

本地socket在使用本地文件路径时,必须是“绝对路径”,这样的话,编写好的程序才可以在任何目录里被启动和管理。如果是“相对路径”,为了保持同样的目的,这个程序的启动路径就必须固定,这样一来,对程序的管理反而是一个很大的负担。

这个本地文件必须是一个“文件”,不能是一个“目录”,如果文件不存在的话,bind操作时会自动创建这个文件。

本地字节流socket和TCP服务器端、客户端编程最大的差异就是socket类型的不同。本地字节流套接字识别服务器不再通过 IP 地址和端口,而是通过本地文件

本地数据报socket编程和UDP编程中不同的是客户端程序需要将本地socket bind到本地的一个路径上,而UDP客户端程序不需要这么做。本地数据报socket这么做的原因是,它需要指定一个本地路径,以便在服务器端回包时,可以正确地找到地址;而在 UDP 客户端程序里,数据是可以通过 UDP 包的本地地址和端口来匹配的(在本地数据报socket的情况下,没有连接,也没有ip和端口,所以只能显示地指定一个标志告诉服务端)。

为什么AF_LOCAL+DGRAM的时候,客户端需要bind一个本地文件?

因为服务器收到来自客户端的数据想要给客户端回复的时候,需要知道发给谁。在其他情况下,服务器都有办法:
1.当使用STREAM时,不管是AF_INET还是AF_LOCAL, 都有连接的概念,所以服务器可以使用原来的连接。
2.当使用AF_INET时,不管是DGRAM还是STREAM, 都能知道对方的ip+port(通过收到的数据包可以得到发送端的本地地址和端口号), 也能确定一个唯一的进程。
只有AF_LOCAL+DGRAM的时候,没有连接,并且也无法获得对方的地址和端口号,所以只能显式的指定一个标志告诉服务端。

当客户端被杀死后(Ctrl+C),服务器端也可以正常退出,引起服务器端正常退出的逻辑是什么?

当客户端强制结束时,操作系统内核会为其向服务器端发送一条结束报(空消息),服务器端read函数会因此返回0,此时服务器端就知道对方已经断开连接。

总结

  • 本地套接字的编程接口和 IPv4、IPv6 套接字编程接口是一致的,可以支持字节流和数据报两种协议
  • 本地套接字的实现效率大大高于 IPv4 和 IPv6 的字节流、数据报套接字实现。