Socket
socket介紹
socket意為套接字,是應用層與傳輸層TCP/IP,UDP之間通訊的中間軟體抽象層,它是一組介面。使用時只需遵循socket的格式與規定去程式設計,讓socket組織資料以符合TCP/UDP協議進行資料的傳輸。
socket的工作流程
先從服務端說起,服務端先初始化socket --> 為此socket繫結埠(bind) --> 監聽此埠(listen) --> 呼叫accept阻塞socket,直到有客戶端連線 --> 如果此時客戶端連線成功(connect),即與服務端完整建立連線,即可開始傳送資料請求(write) --> 伺服器端接收請求並處理請求(read),然後把回應資料傳送給客戶端(write) --> 客戶端讀取響應內容(read) --> 關閉連線,互動結束(close)
scoket初始化->socket.socket()
socket.socket(socket_family,socket_type,protocal=0)
socket_family
AF_INET(ipv4)
AF_INET6 (ipv6)
AF_UNIX(UNIX之間通訊,絕對路徑名)
socket_type
# SOCK_STREAM 提供有序的、可靠的、雙向的和基於連線的位元組流服務,當使用Internet地址族時使用TCP;一般為面向連線的TCP
# SOCK_DGRAM 支援無連線的、不可靠的和使用固定大小(通常很小)緩衝區的資料包服務,當使用Internet地址族使用UDP;一般為非連線的UDP
# SOCK_RAW 原始套接字,允許對底層協議如IP或ICMP進行直接訪問,可以用於自定義協議的開發。
protocal
# IPPROTO_TCP,TCP協議
# IPPROTO_UDP,UPD協議
# 0,如果指定為0,表示由核心根據so_type指定預設的通訊協議
TCP/IP+ipv4
s.socket(socket.AF_INET, socket.SOCK_STREAM)
服務端套接字
s.bind()
用於繫結(主機/ip,埠)到socket套接字, 在AF_INET下,以元組(host,port)的形式表示地址。
s.bind(('xxx.xxx.xxx.xxx',port))
s.listen()
開始TCP監聽。backlog指定在拒絕連線之前,作業系統可以掛起的最大連線數量。該值至少為1,大部分應用程式設為5就可以了。
ps:udp不支援listen()
s.listen(5)
s.accept()
被動接受TCP客戶端連線,(阻塞式)等待連線的到來
ps: udp不支援
conn,addr = s.accept()
關於accept()返回值在官方文件是這麼說的
The return value is a pair (conn, address) where conn is a new socket object usable to send and receive data on the connection, and address is the address bound to the socket on the other end of the connection.
有兩個返回值conn和address,第一個返回值為新的 socket 物件可用於傳送和接受資料,形式大致如下
<socket.socket fd=4, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.124.141', 12345), raddr=('192.168.124.1', 15563)>
address為一個元組,元組包含遠端連線的ip地址和埠,形如
('192.168.124.1', 15563)
客戶端套接字
s.connect()
主動初始化TCP伺服器連線。一般address的格式為元組(主機/ip,port),如果連線出錯,返回socket.error錯誤。
s.connect(('192.168.124.1',22222))
s.connect_ex()
connect()函式的擴充套件版本,出錯時返回出錯碼,而不是丟擲異常
公共用途的套接字函式
s.recv()
socket.recv(bufsize[, flags])
從套接字接收資料。返回值是表示接收到的資料的bytes物件。bufsize指定一次接收的最大資料量。一般為1024
s.recv(1024)
s.send()
傳送資料,將資料傳送到socket套接字。(send在待傳送資料量大於己端快取區剩餘空間時,資料丟失,不會發完)
s.send('This is Socket Client!'.encode('utf-8'))
s.sendall()
傳送完整的TCP資料(本質就是迴圈呼叫send,sendall在待傳送資料量大於己端快取區剩餘空間時,資料不丟失,迴圈呼叫send直到發完)
s.close()
關閉socket 套接字
簡單例子 TCP連線
SocketServer.py
#!/usr/bin/python3
#-*- coding:UTF-8 -*-
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.bind(('192.168.124.141',12345))
phone.listen(5)
conn,addr=phone.accept()
print(conn,addr)
print('Remote IP Address is',addr)
client_msg=conn.recv(1024)
print('client msg: %s' %client_msg)
conn.send(client_msg。upper())
conn.close()
s.close()
SocketClient.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.124.141', 12345))
s.send('this is socket client!'.encode('utf-8'))
res_msg = s.recv(1024)
print(res_msg)
s.close
服務端
客戶端
簡單例子UDP連線
SocketServer.py
#!/usr/bin/python3
#-*- coding:UTF-8 -*-
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
ip = '192.168.124.141'
port = 12346
s.bind((ip,port))
recv_data,addr = s.recvfrom(1024)
print('Client Send Message: %s' %recv_data)
server_send_data = 'this is server!!!'
s.sendto(server_send_data.encode(),addr)
s.close()
SocketClient.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.sendto('this is socket client!!!'.encode('utf-8'),('192.168.124.141',12346))
res_msg,addr = s.recvfrom(1024)
print(res_msg)
s.close()
服務端
客戶端