tcp緩存
socket()模塊函數用法服務器
1 1 import socket 2 2 socket.socket(socket_family,socket_type,protocal=0) 3 3 socket_family 能夠是 AF_UNIX 或 AF_INET。socket_type 能夠是 SOCK_STREAM 或 SOCK_DGRAM。protocol 通常不填,默認值爲 0。 4 4 5 5 獲取tcp/ip套接字 6 6 tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 7 7 8 8 獲取udp/ip套接字 9 9 udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 10 10 11 11 因爲 socket 模塊中有太多的屬性。咱們在這裏破例使用了'from module import *'語句。使用 'from socket import *',咱們就把 socket 模塊裏的全部屬性都帶到咱們的命名空間裏了,這樣能 大幅減短咱們的代碼。 12 12 例如tcpSock = socket(AF_INET, SOCK_STREAM)
服務端套接字函數
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() 建立一個與該套接字相關的文件
tcp是基於連接的,必須先啓動服務端,而後再啓動客戶端去連接服務端
tcp服務端
1 ss = socket() #建立服務器套接字 2 ss.bind() #把地址綁定到套接字 3 ss.listen() #監聽連接 4 inf_loop: #服務器無限循環 5 cs = ss.accept() #接受客戶端連接 6 comm_loop: #通信循環 7 cs.recv()/cs.send() #對話(接收與發送) 8 cs.close() #關閉客戶端套接字 9 ss.close() #關閉服務器套接字(可選)
tcp客戶端
1 cs = socket() # 建立客戶套接字 2 cs.connect() # 嘗試鏈接服務器 3 comm_loop: # 通信循環 4 cs.send()/cs.recv() # 對話(發送/接收) 5 cs.close() # 關閉客戶套接字
socket通訊流程與打電話流程相似,咱們就以打電話爲例來實現一個low版的套接字通訊
服務器端
1 import socket 2 3 phone = socket.socket() #買手機 4 5 phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它,在bind前加 6 phone.bind(('127.0.0.1',8002))#綁定手機號 7 8 phone.listen(5)#開機 設置同時能打進多少個電話 9 10 while True: 11 12 conn,addr = phone.accept() #等待電話 阻塞 13 while True: 14 try: #try 判斷若是客戶端有斷開鏈接的話就終止本次循環 15 msg = conn.recv(1024) #設置接收數據爲1024個字節 16 17 print('msg=%s addr=%s'%(msg,addr)) #查看訪問的客戶端ip 及三次握手的鏈接線路 18 19 conn.send(msg) #發送給客戶機的數據 20 except Exception: 21 break 22 23 conn.close()
客戶端併發
1 import socket 2 3 phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #買手機 裏面的參數能夠不寫默認就是它 4 5 phone.connect(('127.0.0.1',8002)) #打電話 6 7 while True: 8 msg = input('>>>>') 9 if not msg: 10 continue 11 link = phone.send(bytes(msg,encoding='utf-8')) #發送給服務器的數據,必須爲bytes型 12 13 data = phone.recv(1024) #設置接收務器的數據爲1024字節 14 15 print(data.decode('utf-8')) #接收的數據爲bytes型 因此就要轉換成utf-8 16 17 phone.close()
重啓服務端時可能會遇到:socket
這個是因爲你的服務端仍然存在四次揮手的time_wait狀態在佔用地址(若是不懂,請深刻研究1.tcp三次握手,四次揮手 2.syn洪水攻擊 3.服務器高併發狀況下會有大量的time_wait狀態的優化方法)tcp
解決方法:ide
1 #加入一條socket配置,重用ip和端口 2 3 phone=socket(AF_INET,SOCK_STREAM) 4 phone.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它,在bind前加 5 phone.bind(('127.0.0.1',8080))
udp是無連接的,先啓動哪一端都不會報錯函數
udp服務端高併發
1 1 ss = socket() #建立一個服務器的套接字 2 2 ss.bind() #綁定服務器套接字 3 3 inf_loop: #服務器無限循環 4 4 cs = ss.recvfrom()/ss.sendto() # 對話(接收與發送) 5 5 ss.close() # 關閉服務器套接字
udp客戶端oop
cs = socket() # 建立客戶套接字 comm_loop: # 通信循環 cs.sendto()/cs.recvfrom() # 對話(發送/接收) cs.close() # 關閉客戶套接字
udp套接字簡單示例優化
服務器端
1 from socket import * 2 3 ip_prot = ('127.0.0.1',8001) 4 5 szie = 1024 6 udp_sever = socket(AF_INET,SOCK_DGRAM) #注意這裏要選擇udp協議 7 8 udp_sever.bind(ip_prot) 9 10 while True: 11 data,add = udp_sever.recvfrom(szie) 12 13 print('data= %s,add = %s'%(data,add)) 14 15 udp_sever.sendto(bytes('恭喜您傳輸成功',encoding='utf-8'),add) #注意在sendto的時候必須傳上第三個參數add(iP,端口號) 16 17 udp_sever.close()
客戶機
1 from socket import * 2 3 udp_client = socket(AF_INET,SOCK_DGRAM) 4 5 while True: 6 msg = input('>>>>') 7 udp_client.sendto(msg.encode('utf-8'),('127.0.0.1',8001)) #注意在sendto的時候要傳ip參數 8 9 data,add = udp_client.recvfrom(1024) 10 print(data.decode('utf-8')) 11 12 udp_client.close()