Python_unix domain socket(域套接字)

业务上需要实现romd与superd通信,采用的通信协议是:unix domain socket

简介

  • Unix Domain Socket通常称为 【unix域套接口】 或 【本地套接口】,它用于位于同一台机器(操作系统)的进程间通信。它已经被纳入POSIX Operating Systems标准。
    它支持以下三种方式数据传输:
    (1) 可靠的字节流传输(SOCK_STREAM, 对应TCP);
    (2) 无序、不可靠的数据包传输(SOCK_DGRAM,对应UDP)。
    (3)有序、可靠的数据包传输(SOCK_SEQPACKET)原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
    (4)socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RDM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RDM通常仅限于高级用户或管理员运行的程序使用。
    (5)socket.SOCK_SEQPACKET 可靠的连续数据包服务
  • Unix Domain Socket 的通信基于操作系统内核的,使用文件系统作为地址命名空间(address name space)。
  • socket API原本是为网络通讯设计的,但后来在socket的框架上发展出一种IPC机制,就是UNIXDomain Socket。虽然网络socket也可用于同一台主机的进程间通讯(通过loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。UNIX Domain Socket也提供面向流和面向数据包两种API接口,类似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不会丢失也不会顺序错乱。
  • UNIX Domain Socket是全双工的,API接口语义丰富,相比其它IPC机制有明显的优越性,目前已成为使用最广泛的IPC机制,比如X Window服务器和GUI程序之间就是通过UNIX Domain Socket通讯的。
  • 使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。
  • UNIX Domain Socket与网络socket编程最明显的不同在于地址格式不同,用结构体sockaddr_un表示,网络编程的socket地址是IP地址加端口号,而UNIX Domain Socket的地址是一个socket类型的文件在文件系统中的路径,这个socket文件由bind()调用创建,如果调用bind()时该文件已存在,则bind()错误返回。

代码:

以下代码主要讲2种域套接字的通信方式

  • tcp形式的套接字
# server端
import socket
import sys 
import os

serverAddr = './uds_socket' # 套接字存放路径及名称

def serverSocket():
        #create sockert
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)# unix套接字,tcp通信方式
        if sock < 0:
                print >> sys.stderr, 'socket error'
        # bind to a file
        if os.path.exists(serverAddr):
                os.unlink(serverAddr)# 如果套接字存在,则删除
        if sock.bind(serverAddr): #绑定套接字文件,绑定成功后,会在指定路径下生成一个域套接字文件。
                print >> sys.stderr, 'socket.bind error'

        #listen
        if sock.listen(5): #最多监听5个客户端
                print >> sys.stderr, 'socket.listen error'

        while True:
                print >> sys.stderr, 'waiting for connecting'
                #waiting for client connecting
                conn, clientAddr = sock.accept() #如果监听到客户端连接,则调用accept接收这个连接并同时新建一个socket来和客户进行通信
                try:
                        # receive data 
                        # send data to client
                        while True:
                                data = conn.recv(100)#接收100个字节长度的数据
                                if data:
                                        print >> sys.stderr, 'received "%s"' %data
                                        conn.sendall(data)#发送数据
                                else:
                                        break
               except Exception as e :
                        print(e)

if __name__ == "__main__":
        serverSocket()
# client端
import socket
import sys 
import os

serverAddr = './uds_socket' #注意想要跟谁通信就绑定谁的套接字文件

def clientSocket():
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        if sock < 0:
                print >> sys.stderr, 'socket error'

        try:
                sock.connect(serverAddr)
        except socket.error, msg:
                print >> sys.stderr, "exception"
                print >> sys.stderr, msg 
                sys.exit(1)

        message = 'this is the message'
        sock.sendall(message)

        amountRecv = 0 
        amountSnd = len(message)

        while amountRecv < amountSnd:
                data = sock.recv(100)
                amountRecv += len(data)
                print >> sys.stderr, 'received "%s"' %data
        sock.close()

if __name__ == "__main__":
        clientSocket()
  • udp形式的套接字
    注意:udp形式的套接字与tcp最大的不同就是:
    • 它没有server端、client端的区分,意思就是双方各自是独立服务,A想给B发,那么就直接往指定的B的套接字文件发送就可以了
    • 不区分主次,自然也就不需要准入了accept
# coding:utf-8
__author__ = 'xcma'
import socket
import sys
import os

aAddr = './a.sock' # 套接字存放路径及名称
bAddr = './b.sock'
def serverSocket():
        #create sockert
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)# @这里不同   unix套接字,udp通信方式
        if sock < 0:
                print >> sys.stderr, 'socket error'
        # bind to a file
        if os.path.exists(aAddr):
                os.unlink(aAddr)# 如果套接字存在,则删除
        if sock.bind(aAddr): #删除后,绑定套接字文件
                print >> sys.stderr, 'socket.bind error'

        while True:
                print >> sys.stderr, 'waiting for connecting'
                try:
                        # receive data
                        # send data to client
                    while True:
                            data = sock.recv(100)#接收100个字节长度的数据
                            if data:
                                    print >> sys.stderr, 'received "%s"' %data
                                    sock.sendall(data,bAddr)# @ 这里不同 发送数据
                            else:
                                    break
                except Exception as e:
                    print(e)
if __name__ == "__main__":
        serverSocket()

这样如果需要UDP方式,双方通信,各自只需要绑定自己的域套接字文件,然后发送数据的时候指向目标的套接字文件就可以了

总结:

以上只是简单示例,实际应用中保准不能这么用,会显得比较没有层次,而且不容易维护,总的来说用起来还是比较简单的,遇到问题,也比较好查。

你可能感兴趣的:(Python_unix domain socket(域套接字))