业务上需要实现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方式,双方通信,各自只需要绑定自己的域套接字文件,然后发送数据的时候指向目标的套接字文件就可以了
总结:
以上只是简单示例,实际应用中保准不能这么用,会显得比较没有层次,而且不容易维护,总的来说用起来还是比较简单的,遇到问题,也比较好查。
网友评论