Unix Socket - 啥是socket(套接字)?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unix Socket - 啥是socket(套接字)?相关的知识,希望对你有一定的参考价值。

参考技术A         套接字允许在相同或不同机器上的两个不同进程之间进行通信。更准确地说,它是一种使用标准Unix文件描述符与其他计算机通信的方法。在Unix中,每个I/O操作都是通过写入或读取文件描述符来完成的。文件描述符只是一个与打开的文件相关联的整数,它可以是一个网络连接、一个文本文件、一个终端或其他东西。

        对于程序员来说,套接字的外观和行为很像底层的文件描述符。这是因为read()和write()等命令使用套接字的方式与使用文件和管道的方式相同。

        socket最初是在2.1BSD中引入的,随后在4.2BSD中被细化为当前的形式。目前大多数UNIX系统版本都提供了套接字特性。

        在CS应用程序框架中使用Unix套接字。服务是一个根据客户端的请求执行某些功能的进程。大多数应用程序级协议,如FTP、SMTP和POP3,都利用套接字在客户机和服务器之间建立连接,然后进行数据交换。

        有四种类型的套接字可供用户使用。前两种是最常用的,后两种很少使用。

        假定进程只在相同类型的套接字之间通信,但没有限制阻止不同类型的套接字之间通信。

         流套接字 ——保证在网络环境中交付。如果您通过流套接字发送三个项目“A, B, C”,它们将以相同的顺序到达-“A, B, C”。这些套接字使用TCP(传输控制协议)进行数据传输。如果无法投递,发送者将收到一个错误指示符。数据记录没有任何边界。

         数据包套接字 ——不能保证在网络环境中交付。它们是无连接的,因为你不需要像在流套接字中那样有一个打开的连接——你建立一个带有目标信息的包并将它发送出去。它们使用UDP(用户数据包协议)。

         原始套接字 ——这些为用户提供对底层通信协议的访问,这些协议支持套接字抽象。这些套接字通常是面向数据包的,尽管它们的确切特征取决于协议提供的接口。原始套接字不是为一般用户设计的;它们主要是为那些有兴趣开发新通信协议或访问现有协议中一些更神秘的设施的人提供的。

         顺序包套接字 ——它们类似于流套接字,不同的是记录边界被保留。该接口仅作为网络系统(NS)套接字抽象的一部分提供,并且在大多数严肃的NS应用程序中非常重要。顺序包套接字允许用户对一个包或一组包操纵序列(SPP)或网络数据包协议数据报协议(IDP)的报头,通过编写一个标准头,连同任何要发送的数据,或者通过指定一个默认的报头使用所有即将输出的数据,并允许用户接收传入的数据包的报头。

Unix域套接字-Unix Domain Socket(转)

add by zhj: Unix Domain Socket是网络socket的优化,适用于服务端与客户端在同一台机器上的情况。相比网络socket,它可以提高通信效率

原文:https://www.jianshu.com/p/dc78b7ca006a

作者:喵帕斯0_0

来源:简书

最近在搭建Nginx+Gunicorn的时候,返现这两个进程可以通过一个后缀为.sock的文件进行进程之间的通讯,之前遇到的大多数都是通过管道或TCP连接进行通讯,因此花了点时间研究一下。

Nginx中有一段配置是这样的:

  upstream app_server {
    # fail_timeout=0 means we always retry an upstream even if it failed
    # to return a good HTTP response

    # for UNIX domain socket setups
    server unix:/tmp/gunicorn.sock fail_timeout=0;

    # for a TCP configuration
    # server 192.168.0.7:8000 fail_timeout=0;
  }

Unix Domain Socket称为Unix域套接字,简称UDS,是基于Socket API的基础上发展而来的,Socket API原本适用于不同机器上进程间的通讯,当然也可用于同一机器上不同进程的通讯(通过localhost),后来在此基础上,发展出专门用于进程间通讯的IPC机制,UDS与原来的网络Socket相比,仅仅只需要在进程间复制数据,无需处理协议、计算校验和、维护序号、添加和删除网络爆头、发送确认报文,因此更高效,速度更快。UDS提供了和TCP/UDP类似的流和数据包,但这两种都是可靠的,消息不会丢失也不会乱序。

UDS的创建与网络Socket的创建类似:

  1. 创建一个Socket,指定familyAF_UNIXtype支持SOCK_STRAEMSOCK_DGRAM两种;
  2. bind地址,与网络Socket不同,UDS所绑定的对象是一个文件;
  3. 开始监听accept
  4. 接收请求accept,为每个连接建立新的套接字,并从监听队列队列中移除。

下面是一个python写的echo服务器端演示代码:

import socket
import os

server_address = "/Users/Temp/socket.sock"

if os.path.exists(server_address):
    raise Exception("The sock file is exist")

server_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server_socket.bind(server_address)
server_socket.listen(1)

try:
    while True:
        print("Start accept!")

        client_socket,client_address = server_socket.accept()
        
        while True:
            print("Connect from:", client_address)

            data = client_socket.recv(1024)
            if not data:
                print("Connection closed by client!
")
                break
            else:
                print("Received:", data)
                print("Send back:", client_socket.sendall(data))

    os.unlink(server_address)
except Exception as e:
    print(e)
    if os.path.exists(server_address):
        os.unlink(server_address)

UDS的客户端和网络Socket一样,只不过connect的是一个文件,如下是pyrhon写的客户端演示代码:

import socket
import os
import time

server_address = "/Users/Temp/socket.sock"

if not os.path.exists(server_address):
    raise Exception("The sock file is not exist")

print("Connect to socket:", server_address)
client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
    client_socket.connect(server_address)
except Exception as e:
    print(e)
    raise


def send_test(client_socket, send_data):
    time.sleep(1)
    print("Send:", send_data)
    client_socket.send(send_data)
    time.sleep(1)
    recv_data = client_socket.recv(1024)
    print("Echo:", recv_data)


print("Start communication!")
send_data = b"Hello, world!"
send_test(client_socket, send_data)
send_data = b"My name is Tom!"
send_test(client_socket, send_data)
print("Close connection!")
client_socket.close()

运行结果如下:

Connect to socket: /Users/Temp/socket.sock
Start communication!
Send: bHello, world!
Echo: bHello, world!
Send: bMy name is Tom!
Echo: bMy name is Tom!
Close connection!
还有一种简单的方式可以快速的创建非命名的匿名UDS(类似于管道),利用函数socket.socketpair([family[, type[, proto]]]),但这种方式通用性不强,只能用于父子进程之间使用,无法在无关进程中使用。


以上是关于Unix Socket - 啥是socket(套接字)?的主要内容,如果未能解决你的问题,请参考以下文章

Redis-Redis 绑定套接字用unix socket还是tcp socket比较好

Unix域套接字-Unix Domain Socket(转)

如何给UNIX域Socket套接字抓包?

PHP实现系统编程--- 本地套接字(Unix Domain Socket)

Python之socket(套接字)

Socket