1. 簡單的圖解socket流程
2. 連接原理
根據連接啓動的方式以及本地套接字要連接的目標,套接字之間的連接過程可以分爲三個步驟:服務器監聽,客戶端請求,連接確認。
(1)服務器監聽:是服務器端套接字並不定位具體的客戶端套接字,而是處於等待連接的狀態,實時監控網絡狀態。
(2)客戶端請求:是指由客戶端的套接字提出連接請求,要連接的目標是服務器端的套接字。爲此,客戶端的套接字必須首先描述它要連接的服務器的套接字,指出服務器端套接字的地址和端口號,然後就向服務器端套接字提出連接請求。
(3)連接確認:是指當服務器端套接字監聽到或者說接收到客戶端套接字的連接請求,它就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接 字的描述發給客戶端,一旦客戶端確認了此描述,連接就建立好了。而服務器端套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連接請求。
3.1. 案例服務端
# -*- coding:utf8 -*-
import socket
import sys
HOST = '127.0.0.1'
PORT = 8005
# python之socket模塊
def s_server():
s = None
l_data = socket.getaddrinfo(
HOST,
PORT,
socket.AF_UNSPEC,
socket.SOCK_STREAM,
0,
socket.AI_PASSIVE
)
for res in l_data:
af, socketype, proto, canonname, sa = res
try:
s = socket.socket(af, socketype, proto)
except socket.error as msg:
s = None
continue
try:
s.bind(sa)
s.listen(5)
except socket.error as msg:
s.close()
s = None
continue
break
if s is None:
print 'could not open socket'
sys.exit()
return s
if __name__ == '__main__':
s = s_server()
conn, addr = s.accept()
print 'Connected by', addr
while True:
data = conn.recv(1024) # 接收客戶端發送的數據
if not data:
break
conn.send(data) #發送數據到客戶端
conn.close()
getaddrinfo函數源碼:
def getaddrinfo(host, port, family=None, socktype=None, proto=None, flags=None): # real signature unknown; restored from __doc__
"""
getaddrinfo(host, port [, family, socktype, proto, flags])
-> list of (family, socktype, proto, canonname, sockaddr)
Resolve host and port into addrinfo struct.
"""
return []
參數:family(地址簇類型)
socket.AF_UNIX 用與單一機器下的進程通信
socket.AF_INET 用與服務器之間相互通信,通常都用這個。
socket.AF_INET6 支持IPv6
參數:sockettype(socket類型) 常用的有以下幾種socket.SOCK_STREAM 默認,用於TCP協議
socket.SOCK_DGRAM 用於UDP協議
參數:proto (協議)getaddrinnfo函數會根據地址格式和socket類型,返回合適的協議
返回值:canonname
是一個規範化的host name
返回值:sockaddr
是一個二元組,主要用於bind()和connect()函數,
參數:0(默認)
與特定的地址家族相關的協議,如果是0, 則系統就會根據地址格式和套接類別,自動選擇一個合適的協議
創建socket對象:
s = socket.socket(af, socketype, proto)
綁定socket address:
s.bind(sa)
開啓監聽:
s.listen(5)
注意:listen函數會監聽連接到socket上的連接,參數表示在拒絕連接之前系統可以掛起的最大連接隊列數量爲5。這些連接還沒有被accept處理。數量不能無限大,通常指定5
收到監聽調用accept函數接收連接:
conn, addr = s.accept()
注意:accept函數返回一個二元組,conn是一個新的socket對象,用來接收和發送數據。addr表示另一端的socket地址。
conn對象發送和接收數據:
while True:
data = conn.recv(1024) # 接收客戶端發送的數據
if not data:
break
conn.send(data) #發送數據到客戶端
注意:接收到一個連接socket就會停止運行,所以如果要循環連接的話,將accept函數放入到一個死循環裏。3.2. 案例客戶端
# -*- coding:utf8 -*-
import socket
import sys
# python之socket模塊
HOST = '127.0.0.1'
PORT = 8005
def s_client():
s = None
l_data = socket.getaddrinfo(
HOST,
PORT,
socket.AF_UNSPEC,
socket.SOCK_STREAM
)
for res in l_data:
af, socketype, proto, canonname, sa = res
try:
s = socket.socket(af, socketype, proto)
except socket.error as msg:
s = None
continue
try:
s.connect(sa)
except socket.error as msg:
s.close()
s = None
continue
break
if s is None:
print 'could not open socket'
sys.exit(1)
return s
s = s_client()
s.sendall('Hello world!')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
注意:通過connect和服務端建立連接之後,就可以相互通信了
特別注意:以上主要是針對TCP流數據的socket編程。對於UDP協議的數據,處理略有不同。
譬如發送接收UDP數據包處理函數爲:
socket.sendto(string, flags, address)
socket.recvfrom(bufsize[, flags])
# 返回(string, address)
# string是返回的數據,address是發送方的socket地
注意:詳細的TCP與UDP的區別請在詳細的查一查,後續我會添加上
注意:以上內容是個人使用的隨手記錄, 就是介紹了下簡單的使用
歡迎大家來吐槽,準備好瓜子飲料礦泉水,開整!!!
---------------------------------------------------------------------------------------
搞笑一則:能動手儘量別吵吵
注意:以上內容是個人使用的隨手記錄, 就是介紹了下簡單的使用
歡迎大家來吐槽,準備好瓜子飲料礦泉水,開整!!!
---------------------------------------------------------------------------------------