美文网首页测试开发
Python_unix domain socket(域套接字)

Python_unix domain socket(域套接字)

作者: 古佛青灯度流年 | 来源:发表于2018-06-14 22:14 被阅读11次

    业务上需要实现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(域套接字)

        本文链接:https://www.haomeiwen.com/subject/rtyueftx.html