day 30 tcp udp socket編程詳細解說

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)
View Code
服務端套接字函數
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()
View Code

客戶端併發

 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()
View Code

重啓服務端時可能會遇到: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是無連接的,先啓動哪一端都不會報錯函數

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()
相關文章
相關標籤/搜索