業(yè)務(wù)上需要實(shí)現(xiàn)romd與superd通信,采用的通信協(xié)議是:unix domain socket
簡(jiǎn)介
- Unix Domain Socket通常稱(chēng)為 【unix域套接口】 或 【本地套接口】,它用于位于同一臺(tái)機(jī)器(操作系統(tǒng))的進(jìn)程間通信。它已經(jīng)被納入POSIX Operating Systems標(biāo)準(zhǔn)。
它支持以下三種方式數(shù)據(jù)傳輸:
(1) 可靠的字節(jié)流傳輸(SOCK_STREAM, 對(duì)應(yīng)TCP);
(2) 無(wú)序、不可靠的數(shù)據(jù)包傳輸(SOCK_DGRAM,對(duì)應(yīng)UDP)。
(3)有序、可靠的數(shù)據(jù)包傳輸(SOCK_SEQPACKET)原始套接字,普通的套接字無(wú)法處理ICMP、IGMP等網(wǎng)絡(luò)報(bào)文,而SOCK_RAW可以;其次,SOCK_RAW也可以處理特殊的IPv4報(bào)文;此外,利用原始套接字,可以通過(guò)IP_HDRINCL套接字選項(xiàng)由用戶(hù)構(gòu)造IP頭。
(4)socket.SOCK_RDM 是一種可靠的UDP形式,即保證交付數(shù)據(jù)報(bào)但不保證順序。SOCK_RDM用來(lái)提供對(duì)原始協(xié)議的低級(jí)訪問(wèn),在需要執(zhí)行某些特殊操作時(shí)使用,如發(fā)送ICMP報(bào)文。SOCK_RDM通常僅限于高級(jí)用戶(hù)或管理員運(yùn)行的程序使用。
(5)socket.SOCK_SEQPACKET 可靠的連續(xù)數(shù)據(jù)包服務(wù) - Unix Domain Socket 的通信基于操作系統(tǒng)內(nèi)核的,使用文件系統(tǒng)作為地址命名空間(address name space)。
- socket API原本是為網(wǎng)絡(luò)通訊設(shè)計(jì)的,但后來(lái)在socket的框架上發(fā)展出一種IPC機(jī)制,就是UNIXDomain Socket。雖然網(wǎng)絡(luò)socket也可用于同一臺(tái)主機(jī)的進(jìn)程間通訊(通過(guò)loopback地址127.0.0.1),但是UNIX Domain Socket用于IPC更有效率:不需要經(jīng)過(guò)網(wǎng)絡(luò)協(xié)議棧,不需要打包拆包、計(jì)算校驗(yàn)和、維護(hù)序號(hào)和應(yīng)答等,只是將應(yīng)用層數(shù)據(jù)從一個(gè)進(jìn)程拷貝到另一個(gè)進(jìn)程。這是因?yàn)椋琁PC機(jī)制本質(zhì)上是可靠的通訊,而網(wǎng)絡(luò)協(xié)議是為不可靠的通訊設(shè)計(jì)的。UNIX Domain Socket也提供面向流和面向數(shù)據(jù)包兩種API接口,類(lèi)似于TCP和UDP,但是面向消息的UNIX Domain Socket也是可靠的,消息既不會(huì)丟失也不會(huì)順序錯(cuò)亂。
- UNIX Domain Socket是全雙工的,API接口語(yǔ)義豐富,相比其它IPC機(jī)制有明顯的優(yōu)越性,目前已成為使用最廣泛的IPC機(jī)制,比如X Window服務(wù)器和GUI程序之間就是通過(guò)UNIX Domain Socket通訊的。
- 使用UNIX Domain Socket的過(guò)程和網(wǎng)絡(luò)socket十分相似,也要先調(diào)用socket()創(chuàng)建一個(gè)socket文件描述符,address family指定為AF_UNIX,type可以選擇SOCK_DGRAM或SOCK_STREAM,protocol參數(shù)仍然指定為0即可。
- UNIX Domain Socket與網(wǎng)絡(luò)socket編程最明顯的不同在于地址格式不同,用結(jié)構(gòu)體sockaddr_un表示,網(wǎng)絡(luò)編程的socket地址是IP地址加端口號(hào),而UNIX Domain Socket的地址是一個(gè)socket類(lèi)型的文件在文件系統(tǒng)中的路徑,這個(gè)socket文件由bind()調(diào)用創(chuàng)建,如果調(diào)用bind()時(shí)該文件已存在,則bind()錯(cuò)誤返回。
代碼:
以下代碼主要講2種域套接字的通信方式
- tcp形式的套接字
# server端
import socket
import sys
import os
serverAddr = './uds_socket' # 套接字存放路徑及名稱(chēng)
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): #綁定套接字文件,綁定成功后,會(huì)在指定路徑下生成一個(gè)域套接字文件。
print >> sys.stderr, 'socket.bind error'
#listen
if sock.listen(5): #最多監(jiān)聽(tīng)5個(gè)客戶(hù)端
print >> sys.stderr, 'socket.listen error'
while True:
print >> sys.stderr, 'waiting for connecting'
#waiting for client connecting
conn, clientAddr = sock.accept() #如果監(jiān)聽(tīng)到客戶(hù)端連接,則調(diào)用accept接收這個(gè)連接并同時(shí)新建一個(gè)socket來(lái)和客戶(hù)進(jìn)行通信
try:
# receive data
# send data to client
while True:
data = conn.recv(100)#接收100個(gè)字節(jié)長(zhǎng)度的數(shù)據(jù)
if data:
print >> sys.stderr, 'received "%s"' %data
conn.sendall(data)#發(fā)送數(shù)據(jù)
else:
break
except Exception as e :
print(e)
if __name__ == "__main__":
serverSocket()
# client端
import socket
import sys
import os
serverAddr = './uds_socket' #注意想要跟誰(shuí)通信就綁定誰(shuí)的套接字文件
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最大的不同就是:- 它沒(méi)有server端、client端的區(qū)分,意思就是雙方各自是獨(dú)立服務(wù),A想給B發(fā),那么就直接往指定的B的套接字文件發(fā)送就可以了
- 不區(qū)分主次,自然也就不需要準(zhǔn)入了accept
# coding:utf-8
__author__ = 'xcma'
import socket
import sys
import os
aAddr = './a.sock' # 套接字存放路徑及名稱(chēng)
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個(gè)字節(jié)長(zhǎng)度的數(shù)據(jù)
if data:
print >> sys.stderr, 'received "%s"' %data
sock.sendall(data,bAddr)# @ 這里不同 發(fā)送數(shù)據(jù)
else:
break
except Exception as e:
print(e)
if __name__ == "__main__":
serverSocket()
這樣如果需要UDP方式,雙方通信,各自只需要綁定自己的域套接字文件,然后發(fā)送數(shù)據(jù)的時(shí)候指向目標(biāo)的套接字文件就可以了
總結(jié):
以上只是簡(jiǎn)單示例,實(shí)際應(yīng)用中保準(zhǔn)不能這么用,會(huì)顯得比較沒(méi)有層次,而且不容易維護(hù),總的來(lái)說(shuō)用起來(lái)還是比較簡(jiǎn)單的,遇到問(wèn)題,也比較好查。