了解套接字

介绍

接口是允许在服务器上运行的程序之间或在单独的服务器上运行的程序之间进行过程间通信的一种方式,服务器之间的通信依赖于网络接口,这些接口使用互联网协议(IP)来封装和处理发送和接收数据。

客户端和服务器上的网络接口都被称为他们的 socket address. 地址是传输控制协议(TCP)或用户数据图协议(UDP)等传输协议的独特组合,IP地址和端口号。

在本教程中,您将了解用于流程间通信的以下不同类型的接口:

  • _Stream 接口,使用 TCP 作为其基本运输协议
  • _Datagram 接口,使用 UDP 作为其基本运输协议
  • _Unix 域接口,使用本地文件来发送和接收数据,而不是网络接口和 IP 包

在本教程的每个部分中,您还将学习如何在Linux系统上列出相应的接口类型,您将使用各种命令行工具检查每个接口类型。

前提条件

此教程中的示例是在Ubuntu 20.04服务器上验证的,您可以使用本地计算机或远程服务器上的大多数现代Linux发行版使用此教程,只要您安装了每个必要工具的相应版本。

要开始使用 Ubuntu 20.04,您需要一个服务器,该服务器已通过遵循我们的 [Ubuntu 20.04 初始服务器设置( https://andsky.com/tech/tutorials/initial-server-setup-with-ubuntu-20-04)] 指南进行配置。

您还需要一些其他软件包来检查系统上的插件. 使用apt update命令确保系统的软件包缓存处于最新状态:

1sudo apt update

然后使用此命令安装所需的包:

1sudo apt install iproute2 netcat-openbsd socat

iproute2包包含了ss实用程序,这就是我们将用于检查接口的用途。我们将使用netcat-openbsd包来安装netcat。 请注意,当它在命令行上被召唤时,netcat被缩写为nc

什么是Stream Socket?

流接口是面向连接的,这意味着从网络接口发送和接收的包由主机操作系统交付,以便由应用程序进行处理。

TCP 被设计为依靠状态连接的可靠网络协议。使用 TCP 流接口的程序发送的数据将被远程系统成功接收(假设没有路由、防火墙或其他连接问题)。

基于 TCP 的流接口的典型用途是为 Apache 或 Nginx 等 Web 服务器在端口 80 上处理 HTTP 请求,或在端口 443 上使用 HTTPS.对于 HTTP,接口地址类似于 203.0.113.1:80,而对于 HTTPS 则类似于 203.0.113.1:443。

创建基于 TCP 的 Stream Sockets

在下面的示例中,您将使用socat命令(缩写为SOcket CAT)模拟在端口 8080(替代的HTTP端口)上听取HTTP请求的Web服务器,然后使用ssnc命令检查接口。

首先,运行以下socat命令,创建两个基于TCP的接口,以使用IPv4和IPv6接口在端口8080上收听连接:

1socat TCP4-LISTEN:8080,fork /dev/null&
2socat TCP6-LISTEN:8080,ipv6only=1,fork /dev/null&
  • 联合国 TCP4-LITEN:8080'和TCP6-LITEN:8080'的参数是拟使用的协议类型和港号。 他们告诉socat ' 在所有IPv4和IPv6接口上创建 " 8080 " 端口的TCP套接字,并听取每个套接字的输入连接。 socat'可以在系统上的任何可用端口上收听,因此从0'到65535'的任何端口都是套接字选项的有效参数。 () ( )* " 叉 " 选项用于确保 " sockat " 在处理连接后继续运行,否则将自动退出。 () ( )* " dev/null " 路径用于取代远程套接字地址。 在这种情况下,它要求socat ' 打印任何输入到/dev/null'文件的输入,而该文件却默默地放弃了它。 (_) ( )* ipv6 only=1 旗用于 IPv6 套接字, 用于告诉操作系统, 套接字没有被配置到发送包到 [IPv4- mapped IPv6 地址] (https://en.wikipedia.org/wiki/IPv6#IPv4-mapped_IPv6_addresses) 。 如果没有这面旗帜,socat'将约束IPv4和IPv6地址。 (_) ( )* QQ 字符指示 shell 在背景中运行命令 。 此旗帜将确保 sockat` 在您引用其他命令检查套接字时继续运行 。 ( _) (英语)

您将收到如下类型的输出,该输出表示在壳会话背景下运行的两个socat过程ID。

1[secondary_label Output]
2[1] 434223
3[2] 434224

现在你有两个socat流程在背景中倾听TCP端口8080,你可以使用ssnc实用程序来检查接口。

检查基于TCP的流接口

若要使用ss命令检查现代 Linux 系统上的 TCP 接口,请使用以下标志来限制输出:

*46的旗帜告诉ss仅分别检查IPv4或IPv6的插槽。省略此选项将显示两组插槽 *t的旗帜限制输出到TCP的插槽。默认情况下,ss工具将显示在Linux系统上使用的所有类型的插槽 *l的旗帜将输出限制在听取的插槽上。没有这个旗帜,所有TCP连接将显示,这将包括诸如SSH,客户端可能连接到Web服务器,或您的系统可能与其他服务器的连接 *n的旗帜确保端口号显示而不是服务名称

首先运行ss -4 -tln命令来检查正在听取系统上的连接的IPv4 TCP基于接口:

1ss -4 -tln

您将收到如下的输出:

1[secondary_label Output]
2State Recv-Q Send-Q Local Address:Port Peer Address:Port Process     
3. . .
4LISTEN 0 1 0.0.0.0:8080 0.0.0.0:*
5. . .

输出中可能有其他端口的线条,取决于您的系统上运行哪些服务。输出中突出的0.0.0.0:8080部分表示IPv4 TCP接口在端口8080上的所有可用的IPv4接口上倾听。

现在再次运行相同的ss命令,但使用6旗:

1ss -6 -tln

您将收到如下的输出:

1[secondary_label Output]
2State Recv-Q Send-Q Local Address:Port Peer Address:Port Process  
3. . .
4LISTEN 0 5                   [::]:8080               [::]:*
5. . .

输出中可能有其他端口的线条,取决于您的系统上运行哪些服务。输出中标注的[::]:8080部分表示IPv6 TCP接口在端口8080上的所有可用IPv6接口上正在收听(标注为::字符,这些字符是由所有零组成的IPv6地址的标注)。

连接到基于 TCP 的流接口

到目前为止,您已经学会了如何在 IPv4 和 IPv6 界面上创建和列举 TCP 接口. 现在您有两个接口聆听连接,您可以尝试使用 netcat 实用程序连接到接口。

使用netcat来测试TCP连接到本地和远程接口是一个非常有用的故障排除技术,可以帮助系统之间隔离连接和防火墙问题。

若要通过使用 netcat 连接到 IPv4 接口的本地 loopback 地址,请执行以下命令:

1nc -4 -vz 127.0.0.1 8080
  • -4 标志告诉 netcat 使用 IPv4.
  • -v 标志用于打印到您的终端的语音输出
  • -z 选项确保 netcat 只连接到接口,而不会发送任何数据
  • 使用本地回路地址 127.0.0.0.1 IP 地址,因为您的系统将有自己的独特的 IP 地址。

您将收到如下的输出:

1[secondary_label Output]
2Connection to 127.0.0.1 (127.0.0.1) 8080 port [tcp/http-alt] succeeded!

突出的线是来自 netcat 的输出,它表示 netcat 已连接到 TCP 接口,在端口 80 上的 loopback 127.0.0.1 IPv4 地址上收听。

现在你可以重复同样的连接测试,但使用IPv6。

1nc -6 -vz ::1 8080

您应该获得如下类型的输出:

1[secondary_label Output]
2Connection to ::1 8080 port [tcp/http] succeeded!

突出的线是来自 netcat 的输出,表明 netcat 已连接到 TCP 接口,并在端口 8080 上的 loopback ::1` IPv6 地址上收听。

要清理您的插槽,您需要为您创建的每个socat过程运行fg命令,然后您将使用CTRL+C来关闭每个socat。

运行fg以将第二个 IPv6 socat 实例带到终端的前沿,然后运行CTRL+C来关闭它。

1fg

您将收到如下的输出:

1[secondary_label Output]
2socat TCP6-LISTEN:8080,ipv6only=1,fork /dev/null

CTRL+C来停止这个过程。

现在再运行fg来清理第一个IPv4插槽,您应该有如下类似的输出:

1[secondary_label Output]
2socat TCP4-LISTEN:8080,fork /dev/null

CTRL+C来停止这个过程。

这些技术和工具将在本地开发系统或远程生产服务器上工作,所以尝试尝试每个工具,以便更熟悉如何使用它们来测试和解决TCP插件。

什么是Datagram Socket?

Datagram 接口是无连接的,这意味着从接口发送和接收的包由应用程序单独处理。

UDP 不会在包标题中编码序列信息,并且没有内置错误纠正程序。使用基于 datagram 的网络接口的程序必须建立自己的错误处理和数据排序逻辑,以确保成功的数据传输。

UDP 接口通常由域名系统 (DNS) 服务器使用。默认情况下,DNS 服务器使用端口 `53’ 来发送和接收域名查询。

<$>[注] :虽然该协议不包括在可人读的接口地址版本中,但操作系统通过将TCP和UDP协议作为地址的一部分来区分接口地址,因此可以使用203.0.113.1:53等可人读的接口地址。

网络时间协议 (NTP) 使用在端口123上的 UDP 接口来同步计算机之间的时钟. NTP 协议的 UDP 接口的例子是203.0.113.1:123

创建 Datagram 接口

与之前的 TCP 接口示例一样,在本节中,您将再次使用socat来模拟一个 NTP 服务器在 UDP 端口123上听取请求。

首先,运行以下socat命令来创建两个倾听在端口123上的连接的UDP接口,使用IPv4和IPv6接口:

1sudo socat UDP4-LISTEN:123,fork /dev/null&
2sudo socat UDP6-LISTEN:123,ipv6only=1,fork /dev/null&

您将收到如下类型的输出,该输出表示在壳会话背景下运行的两个socat过程ID。

1[secondary_label Output]
2[1] 465486
3[2] 465487

每个命令都以sudo为前缀,因为01024的端口在大多数系统上都是保留的。sudo运行一个具有管理员权限的命令,允许socat连接到保留范围内的任何端口 *UDP4-LISTEN:123UDP6-LISTEN:123的论点是要使用的协议类型和端口。他们告诉SOCAT在IPv4和IPv6界面上创建基于UDP的端口123,并聆听输入数据。 再一次,0-65535的整个范围内的任何端口都是UDP端口的有效参数 *forkip,v6only=1和`dev/null

现在你有两个socat流程在UDP端口123上聆听,你可以使用ssnc实用程序检查接口。

查看数据图索克

要使用ss命令检查现代 Linux 系统上的 UDP 插槽,请使用以下-4, -6uln旗帜来限制输出:

u 旗限制输出到 UDP 接口 其他旗帜与上一个 TCP 示例中使用的旗帜相同。

首先运行ss -4 -uln命令来检查正在听取系统上的连接的 IPv4 UDP 接口:

1ss -4 -uln

您将收到如下的输出:

1[secondary_label Output]
2State Recv-Q Send-Q Local Address:Port Peer Address:Port Process     
3. . .
4UNCONN 0 0 0.0.0.0:123 0.0.0.0:*
5. . .

输出中可能有其他端口的线条,取决于您的系统上运行哪些服务。输出中标注的0.0.0.0:123部分表示IPv4 UDP接口在端口123上的所有IPv4接口上可用。

现在再次运行相同的ss命令,但使用6旗:

1ss -6 -uln

您将收到如下的输出:

1[secondary_label Output]
2State Recv-Q Send-Q Local Address:Port Peer Address:Port Process  
3. . .
4UNCONN 0 0                   [::]:123              [::]:*
5. . .

输出中可能有其他端口的线条,取决于您的系统上运行哪些服务。输出中突出的[::]:123部分表示 IPv6 TCP 接口可在所有 IPv6 接口上使用123 (如::字符所示)。

测试DataGram接口

现在你已经熟悉如何在 IPv4 和 IPv6 界面上创建和列举 UDP 接口,你可以尝试连接到它们。

要连接到您在本教程的上一节创建的端口123上的 UDP 插槽示例,请运行以下 netcat 命令:

1nc -4 -u -vz 127.0.0.1 123
  • -4 旗告诉 netcat 使用 IPv4.
  • -u 选项指示 netcat 使用 UDP 而不是 TCP.
  • -v 旗被用来打印 verbose 输出到您的终端
  • -z 选项确保 netcat 只连接到接口,而不会发送任何数据
  • 使用本地循环 IP 地址 127.0.0.0.1 因为您的系统将有自己的独特 IP 地址。

您将收到如下的输出:

1[secondary_label Output]
2Connection to 127.0.0.1 123 port [udp/ntp] succeeded!

输出表明,netcat _未收到从127.0.0.1端口上的127.0.0.1 IPv4 地址上收听 UDP 接口的错误。 这种缺失的错误响应被用来推断127.0.0.1:123的接口是可用的。

<$>[注] **注:**如果本示例中的接口不可用,远程系统将返回一个 ICMP 类型 3 (目的地不可及) 消息,代码为 3,表示该端口在远程主机上不可及。

假定插件基于缺失错误响应而可用,就假定没有阻止 ICMP 流量的防火墙或连接问题. 没有通过 UDP 插件发送、接收和验证应用程序数据,就没有保证远程 UDP 端口会打开并接受包。

现在你可以重复同样的连接测试,但使用IPv6。

1nc -6 -u -vz ::1 123

您应该获得如下类型的输出:

1[secondary_label Output]
2Connection to ::1 123 port [udp/ntp] succeeded!!

输出表明,netcat 没有收到来自 UDP 接口在端口 123 上的 loopback ::1` IPv6 地址上收听的错误_。

要清理您的插槽,您需要为您创建的每个 socat 流程运行fg命令,然后使用CTRL+C来关闭每个 socat。

运行fg以将第二个IPv6socat实例带到终端的前面,然后运行CTRL+C来关闭它。

1fg

您将收到如下的输出:

1[secondary_label Output]
2sudo socat UDP6-LISTEN:123,ipv6only=1,fork /dev/null

CTRL+C来停止这个过程。

现在再运行fg来清理第一个IPv4插槽,您将有如下类似的输出:

1[secondary_label Output]
2sudo socat UDP4-LISTEN:123,fork /dev/null

CTRL+C来停止这个过程。

您现在已经在您的系统上创建、检查并测试了 IPv4 和 IPv6 UDP 接口. 尝试尝试每个工具,以便更熟悉它们如何用于测试和故障排除 UDP 接口。

什么是Unix Domain Socket?

运行在同一服务器上的程序也可以使用Unix Domain Sockets(UDS)相互通信。Unix Domain Sockets可以基于流或基于数据格。使用域插件时,通过主机文件系统上的文件直接在操作系统内间交换数据。为了使用域插件发送或接收数据,程序可以读取和写入其共享的插件文件,完全绕过基于网络的插件和协议。

Unix Domain Sockets 被不需要连接到网络接口的数据库系统广泛使用,例如,Ubuntu 上的 MySQL 默认使用名为 `/var/run/mysqld/mysql.sock 的文件与本地客户端进行通信。

PostgreSQL 是另一个数据库系统,用于本地,非网络通信使用插件. 通常它默认使用 /run/postgresql/.s.PGSQL.5432 作为插件文件。

创建 Unix 域名插件

在之前的部分中,您探讨了如何使用TCP与流接口,以及如何使用UDP与数据图接口。在本节中,您将使用socat创建基于流和数据图的Unix域接口,而不使用TCP或UDP来封装数据以通过网络发送。

要开始,运行以下socat命令来创建两个接口文件:

1socat unix-listen:/tmp/stream.sock,fork /dev/null&
2socat unix-recvfrom:/tmp/datagram.sock,fork /dev/null&
  • 第一個命令指示 socat 使用「unix-listen」地址類型創建一個接口,這將創建一個基於流程的 UDS.
  • 第二個命令指定「unix-recvfrom」為接口類型,這將創建一個基於 datagram 的 UDS
  • 兩個命令都會在 : 分離器後指定一個檔案名稱。 檔案名稱是接口本身的地址。 對於第一個流程示例來說,它是 /tmp/stream.sock,而對於第二個 datagram 示例來說,它是 /tmp/datagram.sock。 請注意,接口的名稱是任意的,但如果您正在解決問題時,它

现在你已经创建了你的两个UDS插槽,你可以使用ssnc实用程序来检查它们。

查看 Unix 域名插件

要列出所有正在收听的 Unix 域插件,请运行 ss -xln 命令. x 旗帜确保只显示域插件。

1ss -xln

您将收到如下的输出:

1[secondary_label Output]
2Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
3. . .
4u_str LISTEN 0 5        /tmp/stream.sock 436470            * 0             
5u_dgr UNCONN 0 0      /tmp/datagram.sock 433843            * 0
6 . . .

注意/tmp/stream/sock线的突出u_str部分. 此字段表示插槽类型是基于流的 UDS. 第二行显示类型是u_dgr,这意味着插槽类型是基于数据图的。

由于Unix Domain Sockets是文件,通常的Linux用户和群组权限和访问控制可以用来限制谁可以连接到插件. 您还可以使用lsmvchownchmod等文件系统工具来检查和操纵UDS文件。

要检查文件是否是UDS插件,请使用lsfilestat实用工具,但重要的是要注意,这些工具都不能确定UDS是否是基于流或基于数据图。

要检查文件系统上的插槽,stat实用程序会显示最相关的信息,然后在您之前创建的插槽上运行:

1stat /tmp/stream.sock /tmp/datagram.sock

您将收到如下的输出:

 1[secondary_label Output]
 2  File: /tmp/stream.sock
 3  Size: 0 Blocks: 1 IO Block: 131072 socket
 4Device: 48h/72d Inode: 1742 Links: 1
 5Access: (0755/srwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
 6Access: 2021-03-01 18:10:25.025755168 +0000
 7Modify: 2021-03-01 18:10:25.025755168 +0000
 8Change: 2021-03-01 18:22:42.678231700 +0000
 9 Birth: -
10  File: /tmp/datagram.sock
11  Size: 0 Blocks: 1 IO Block: 131072 socket
12Device: 48h/72d Inode: 1743 Links: 1
13Access: (0755/srwxr-xr-x)  Uid: (    0/    root)   Gid: (    0/    root)
14Access: 2021-03-01 18:10:25.025755168 +0000
15Modify: 2021-03-01 18:10:25.025755168 +0000
16Change: 2021-03-01 18:10:25.025755168 +0000
17 Birth: -

请注意,对于每个文件,类型为插件(在输出的右边突出),并且访问模式有一个s字符,在文件的权限之前。

ls实用程序还会显示一个文件是否是一个插槽。运行ls -l来检查文件:

1ls -l /tmp/stream.sock /tmp/datagram.sock

您将收到如下输出. 再次注意,对于插槽,文件模式包括文件权限字段前的 `s' 字符:

1[secondary_label Output]
2srwxr-xr-x 1 root root 0 Mar 1 18:10 /tmp/datagram.sock
3srwxr-xr-x 1 root root 0 Mar 1 18:10 /tmp/stream.sock

现在你已经创建了Unix Domain Sockets,并学会了如何使用ss和各种基于文件系统的工具来检查它们,下一步是使用像netcat这样的工具来测试插件。

测试 Unix 域名插件

netcat 实用程序可以用来连接到 Unix Domain Sockets 以及您在本教程中早些时候了解的 TCP 和 UDP 接口. 要连接到您创建的示例接口,您需要在运行 netcat 命令时指定额外的 -U 旗帜。

此外,如果接口是基于数据图的,你会使用u旗号来指示netcat使用数据图,正如我们在本教程的数据图接口部分中所学到的。

让我们开始通过使用以下命令连接到基于流的接口来检查UDS接口:

1nc -U -z /tmp/stream.sock

-U告诉netcat它正在连接到一个Unix域连接器 -z’选项确保netcat只连接到一个连接器,而不会发送任何数据 /tmp/stream.sock`是文件系统上的连接器的地址。

当您运行命令时,您将不会收到来自 netcat 的任何输出。

1[secondary_label Output]
2nc: unix connect failed: No such file or directory
3nc: /tmp/stream.sock: No such file or directory

因此,在测试基于流的UDS接口时没有来自netcat的输出意味着连接成功。

重复测试过程,这一次是基于数据图的 UDS:

1nc -uU -z /tmp/datagram.sock

添加了额外的u旗,告诉netcat,远程接口是数据图接口. 再次,如果测试成功,您将不会收到任何输出。

如果地址没有接口,您将收到如下错误:

1[secondary_label Output]
2nc: unix connect failed: No such file or directory
3nc: /tmp/datagram.sock: No such file or directory

要清理您的插槽,您需要为您创建的每个 socat 流程运行fg命令,然后使用CTRL+C来关闭每个 socat。

运行fg,将基于数据图的socat实例带到您的终端的前沿:

1fg

您将收到如下的输出:

1[secondary_label Output]
2socat unix-recvfrom:/tmp/datagram.sock,fork /dev/null

点击 CTRL + C 来关闭它,您将不会收到任何输出。

现在,再次运行fg,以清理第一个基于流的 UDS 接口。

再次,你应该有如下这样的输出:

1[secondary_label Output]
2socat unix-listen:/tmp/stream.sock,fork /dev/null

运行CTRL+C来结束过程,您将不会收到任何输出。

您现在已经在您的系统上创建,检查和测试了 Unix Datagram Sockets 接口. 尝试使用 netcat 和'socat' 来了解如何通过 UDS 发送和接收数据,以及如何测试和修复 Unix 域接口。

结论

在本教程中,您探索了如何在Linux系统上使用不同类型的接口. 您了解了基于流的接口,这些接口通常用于网络通信。 您还了解了基于数据图的接口,这些接口使用UDP来通过网络发送数据。

在每个部分中,您使用了ss实用程序来收集有关 Linux 系统上的插槽的信息,您了解了ss工具提供的不同旗帜如何帮助您在检查系统上的插槽时将其输出限制在特定类型的插槽上。

最后,你使用了netcat和socat工具来创建和连接到本教程中讨论的三个不同类型的接口中的每一个。netcat实用程序被广泛用于连接到接口,但它也可以创建接口。它的文档(man nc)包含许多例子,如何在两种模式中使用。socat实用程序是一个更先进的工具,可以用来连接到和许多不同类型的接口,这些不包括在本教程中。

了解插件是什么以及它们如何工作是一个核心系统管理技能,您在本教程中实验的工具和技术将帮助您更熟悉插件,以及如果您的服务器和应用程序不正确地相互通信,如何解决问题。

Published At
Categories with 技术
Tagged with
comments powered by Disqus