一、Linux Socket
1.Linux Socke基本上就是BSD Socket(伯克利套接字)
伯克利套接字的應用編程接口(API)是采用C語言的進程間通信的庫,經常用在計算機網絡間的通信。BSD Socket的應用編程接口已經是網絡套接字的抽象標准。大多數其他程序語言使用一種相似的編程接口。由於伯克利套接字是第一個socket,大多數程序員很熟悉它們,所以大量系統把伯克利套接字作為其主要的網絡API。
主要的頭文件如下,不同的系統可能具體不同。
<sys/socket.h> BSD socket 核心函數和數據結構。
<netinet/in.h> AF_INET 和AF_INET6 地址家族和他們對應的協議家族PF_INET 和PF_INET6。在互聯網編程中廣泛使用,包括IP地址以及TCP和UDP端口號。
<sys/un.h> PF_UNIX/PF_LOCAL 地址家族。用於運行在一台計算機上的程序間的本地通信,不用在網絡中。
<arpa/inet.h> 和IP地址相關的一些函數。
<netdb.h> 把協議名和主機名轉化成數字的一些函數。
2.API函數
這些是伯克利套接字提供的庫函數:
(1)socket() 創造某種類型的套接字,分配一些系統資源,用返回的整數識別。
(2)bind() 一般是用在服務器這邊,和一個套接字地址結構相連,比如說是一個特定的本地端口號和一個IP地址。
(3)listen()用在服務器一邊,導致一個綁定的TCP套接字進入監聽狀態。
(4)connect() 用在客戶機這邊,給套接字分配一個空閑的端口號。比如說一個TCP套接字,它會試圖建立一個新的TCP連接。
(5)accept() 用在服務器這邊。從客戶機那接受請求試圖創造一個新的TCP連接,並把一個套接字和這個連接相聯系起來。
(6)send() and recv(), or write() and read(),or sendto() and recvfrom()用來接收和發送數據。
(7)close() 關閉連接,系統釋放資源。
(8)gethostbyname() and gethostbyaddr()用來解析主機名和地址。
(9)select() 、poll() 處理多個連續的讀、寫餓錯誤狀態。
(11)getsockopt() 得到對應socket的選項值。
(12)setsockopt() 設置對應socket的選項值。
二、Python實現網絡通信
網絡上的兩個程序通過一個雙向的通信連接實現數據的交換,這個連接的一端稱為一個socket。python中socket模塊為操作系統的socket實現提供了一個python接口。
1.socket的相關函數:
(1)socket():用於創建與指定的服務提供者綁定socket。
函數原型為:socket=socket.socket(familly,type)
參數說明:
familly:指定協議的地址家族,可為AF_INET或AF_UNIX。AF_INET家族包括Internet地址,AF_UNIX家族用於同一台機器上的進程間通信。
type:指定套接字的類型。
(2)bind():bind()函數可以將本地地址與一個socket綁定在一起.
函數原型為:socket.bind( address )
參數address是一個雙元素元組,格式是(host,port)。host代表主機,port代表端口號。
(3)listen():listen()函數可以將socket設置為監聽接入連接的狀態。
函數原型為:listen(backlog)
參數backlog指定等待連接隊列的最大長度。
(4)connect():connect()函數用於連接到address處的socket。
函數原型為:socket.connect(address)
參數address是一個雙元素元組,格式是(host,port)。host代表主機,port代表端口號
(5)accept():在服務器端調用listen()函數監聽接入連接后,可以調用accept()函數來等待接受連接請求。
函數原型為:(connection,address)=socket.accept()
用accept()方法后,socket會進入waiting狀態。客戶請求連接時,accept()方法會建立連接並返回服務器。accept()方法返回一個含有兩個元素的元組(connection,address)。第一個元素connection是新的socket對象,服務器必須通過它與客戶通信;第二個元素address是客戶的Internet地址。
(6)recv():調用recv()函數可以從已連接的socket中接收數據。
函數原型為:buf = sock.recv(size)
參數sock是接收數據的socket對象,參數size指定接收數據的緩沖區的大小。recv()的函數的返回接收的數據。
(7)send():調用send()函數可以在已連接的socket上發送數據。
函數原型為:sock.recv(buf)
參數sock是在已連接的socket上發送數據。參數buf是也要已連接的Socket上發送數據。
(8)close():close ()函數用於關閉一個socket,釋放其所占用的所有資源。
函數原型為:sock.closesocket();
參數s表示要關閉的socket。
可以在Linux系統下查看socket模塊:
通過比較可以看出,再socket模塊中並沒有上述的bind(),listen(),accept()等函數。
這是因為它們都是繼承自_socket模塊。而_socket是在鏈接庫里的,也就是說它不是用python實現的,而是socket操作的C實現,這個是非常底層的操作。socket.py是用py代碼把C實現的模塊的封裝起來之后的模塊,供人使用,在不同系統_socket的位置不一樣。
再查看_socket模塊:
這下可以看到我們在編程中需要用到的那些函數了。
2.TCP/編程實現:
socket編程需要兩端,一般來說,需要一個服務端(Server),一個客戶端(Client)。如圖:
TCP服務端編程:
服務端連接步驟:
(1)創建socket對象
(2)使用bind方法,綁定IP地址,Address和端口Port
(3)使用listen開始監聽,在上面以綁定的地址上
(4)使用accept開始等待連接進來,獲取用於傳送數據的socket對象和addr。注意使用accept會發生阻塞,慣用放在新的線程里面
(5)接收數據recv
代碼:
import socket sk = socket.socket() # 默認是AF_INET、SOCK_STREAM address = ('127.0.0.1', 9000) sk.bind(address) # 將主機號與端口綁定到套接字 sk.listen(3) # 設置並啟動TCP監聽器 print('waitting......') while True: conn, addr = sk.accept() # 被動接受TCP連接,一直等待連接到達 print('連接到達',addr) while True: data = conn.recv(1024) # 接收TCP消息,並制定最大長度 if not data: print('連接已斷開!') conn.close() break print(str(data, 'utf8')) inp = input('>>') conn.send(bytes(inp, 'utf8')) #向客戶端回送信息
TCP客戶端編程:
客戶端連接步驟:
(1)創建Socket對象
(2)連接到遠端服務端的IP和port端口, connect方法
(3)傳輸數據:send發送數據;recv接收數據, 會阻塞
(4)關閉連接,釋放資源
代碼:
import socket
sk = socket.socket() # 默認是AF_INET、SOCK_STREAM address = ('127.0.0.1', 9000) sk.connect(address) #連接服務端 while True: inp = input('>>') if inp == 'exit': break sk.send(bytes(inp, 'utf8')) #向服務端發送信息 data = sk.recv(1024) print(str(data, 'utf8')) else: sk.close()
運行結果:
服務端:
客戶端: