pythonsocket編程2
1 套接字發展史及發展
套接字起源於 20 世紀 70 年代加利福尼亞大學伯克利分校版本的 Unix,即人們所說的 BSD Unix。 因此,有時人們也把套接字稱為“伯克利套接字”或“BSD 套接字”。一開始,套接字被設計用在同 一臺主機上多個應用程序之間的通訊。這也被稱進程間通訊,或 IPC。套接字有兩種(或者稱為有兩個種族),分別是基於文件型的和基於網絡型的。
基於文件類型的套接字家族
套接字家族的名字:AF_UNIX
unix一切皆文件,基於文件的套接字調用的就是底層的文件系統來取數據,兩個套接字進程運行在同一機器,可以通過訪問同一個文件系統間接完成通信
基於網絡類型的套接字家族
套接字家族的名字:AF_INET
(還有AF_INET6被用於ipv6,還有一些其他的地址家族,不過,他們要麽是只用於某個平臺,要麽就是已經被廢棄,或者是很少被使用,或者是根本沒有實現,所有地址家族中,AF_INET是使用最廣泛的一個,python支持很多種地址家族,但是由於我們只關心網絡編程,所以大部分時候我麽只使用AF_INET)
網絡類型分為TCP和UDP兩種
2 套接字工作流程(tcp)
TCP 傳輸控制協議
Tcp是可靠傳輸,發送包在對方返回收到信息後刪除包
先從服務器端說起。服務器端先初始化Socket,然後與端口綁定(bind),對端口進行監聽(listen),調用accept阻塞,等待客戶端連接。在這時如果有個客戶端初始化一個Socket,然後連接服務器(connect),如果連接成功,這時客戶端與服務器端的連接就建立了。客戶端發送數據請求,服務器端接收請求並處理請求,然後把回應數據發送給客戶端,客戶端讀取數據,最後關閉連接,一次交互結束
模擬練習: #服務器 phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#SOCK_STREAM是TCP協議 phone.bind(("127.0.0.1",8080))#綁定手機卡 綁定(主機,端口號)到套接字 phone.listen(5)#listen的功能:建立連接 開機 開始TCP監聽 while True:#連接循環 conn,addr=phone.accept()#等待電話連接 被動接受TCP客戶的鏈接 print("電話線路是",conn) print("客戶端的手機號是",addr) # conn.recv(1024)收消息 while True: try: data=conn.recv(1024)#接收TCP數據,1024是最大限額或者8192 print("客戶端發來的消息是",data) conn.send(data.upper())#發送TCP數據 except Exception: break conn.close() phone.close() #客戶端 import socket phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#買手機 phone.connect(("127.0.0.1",8080))#主動初始化TCP服務器連接 while True:#通信循環 msg=input(">>") if not msg:continue#輸入信息不能為空 phone.send(msg.encode("utf8"))#發送TCP數據 data=phone.recv(1024) print(data) phone.close()#關閉套接字
服務端套接字函數 s.bind() 綁定(主機,端口號)到套接字 s.listen() 開始TCP監聽 s.accept() 被動接受TCP客戶的鏈接,(阻塞式)等待連接的到來 客戶端套接字函數 s.connect() 主動初始化TCP服務器連接 s.connect_ex() connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常 公共用途的套接字函數 s.recv() 接收TCP數據 s.send() 發送TCP數據(send在待發送數據量大於己端緩存區剩余空間時,數據丟失,不會發完) s.sendall() 發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端緩存區剩余空間時,數據不會丟失,循環調用send直到發完) s.recvfrom() 接收UDP數據 s.sendto() 發送UDP數據 s.getpeername() 連接到當前套接字的遠端的地址 s.getsockname() 當前套接字的地址 s.getsockopt() 返回指定套接字的參數 s.setsockopt() 設置指定套接字的參數 s.close() 關閉套接字 面向鎖的套接字方法 s.setblocking() 設置套接字的阻塞與非阻塞模式 s.settimeout() 設置阻塞套接字操作的超時時間 s.gettimeout() 得到阻塞套接字操作的超時時間 面向文件的套接字的函數 s.fileno() 套接字的文件描述符 s.makefile() 創建一個與該套接字相關的文件
可能遇到的問題
這個由於服務端仍然在四次揮手的time_wait狀態在占用地址
解決方案: 加入一條socket配置,重用ip和端口 phone=socket(AF_INET,SOCK_STREAM) phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加 phone.bind((‘127.0.0.1‘,8080)) 發現系統存在大量TIME_WAIT狀態的連接,通過調整linux內核參數解決, vi /etc/sysctl.conf 編輯文件,加入以下內容: net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_fin_timeout = 30 然後執行 /sbin/sysctl -p 讓參數生效。 net.ipv4.tcp_syncookies = 1 表示開啟SYN Cookies。當出現SYN等待隊列溢出時,啟用cookies來處理,可防範少量SYN攻擊,默認為0,表示關閉; net.ipv4.tcp_tw_reuse = 1 表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉; net.ipv4.tcp_tw_recycle = 1 表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。 net.ipv4.tcp_fin_timeout 修改系統默認的 TIMEOUT 時間
python\socket編程2