1. 程式人生 > >pythonsocket編程2

pythonsocket編程2

ron add 隊列 locking socket編程 套接字函數 png 程序 丟失

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