Python網絡編程—socket套接字編程(TCP)


套接字介紹

1.套接字 : 實現網絡編程進行數據傳輸的一種技術手段

2.Python實現套接字編程:import socket

3.套接字分類

  • 流式套接字(SOCK_STREAM): 以字節流方式傳輸數據,實現tcp網絡傳輸方案。(面向連接--tcp協議--可靠的--流式套接字)
  • 數據報套接字(SOCK_DGRAM):以數據報形式傳輸數據,實現udp網絡傳輸方案。(無連接--udp協議--不可靠--數據報套接字)

tcp套接字

服務端流程

1.創建套接字

sockfd=socket.socket(socket_family=AF_INET,socket_type=SOCK_STREAM,proto=0)

  • 功能:創建套接字
  • 參數: socket_family 網絡地址類型 AF_INET表示ipv4
  •     socket_type 套接字類型 SOCK_STREAM(流式) SOCK_DGRAM(數據報)
  •     proto 通常為0 選擇子協議
  • 返回值: 套接字對象

2.綁定地址

本地地址 : 'localhost' , '127.0.0.1'
網絡地址 : '172.40.91.185'
自動獲取地址: '0.0.0.0'

sockfd.bind(addr)

  • 功能: 綁定本機網絡地址
  • 參數: 二元元組 (ip,port) ('0.0.0.0',8888)

3.設置監聽

sockfd.listen(n)

  • 功能 : 將套接字設置為監聽套接字,確定監聽隊列大小
  • 參數 : 監聽隊列大小

4.等待處理客戶端連接請求

connfd,addr = sockfd.accept()

  • 功能: 阻塞等待處理客戶端請求
  • 返回值: connfd 客戶端連接套接字
  •     addr 連接的客戶端地址

5.消息收發

data = connfd.recv(buffersize)

  • 功能 : 接受客戶端消息
  • 參數 :每次最多接收消息的大小
  • 返回值: 接收到的內容

n = connfd.send(data)

  • 功能 : 發送消息
  • 參數 :要發送的內容 bytes格式
  • 返回值: 發送的字節數

6.關閉套接字

sockfd.close()

  • 功能:關閉套接字
tcp服務端流程

客戶端流程

1.創建套接字

注意:只有相同類型的套接字才能進行通信

2.請求連接

sockfd.connect(server_addr)

  • 功能:連接服務器
  • 參數:元組 服務器地址

3.收發消息

注意: 防止兩端都阻塞,recv send要配合

4.關閉套接字

 1 """
 2 重點代碼
 3 """
 4 
 5 from socket import *
 6 
 7 # 創建tcp套接字
 8 sockfd = socket() # 參數默認即tcp套接字
 9 
10 # 連接服務端程序
11 server_addr = ("172.40.91.150",8888)  # 服務端地址
12 sockfd.connect(server_addr)
13 
14 while True:
15   # 消息發送接收
16   data = input("Msg>>")
17   # 如果直接回車,則跳出循環
18   if not data:
19     break
20   sockfd.send(data.encode()) # 轉換字節串發送
21   data = sockfd.recv(1024)
22   print("Server:",data.decode())
23 
24 sockfd.close()
tcp客戶端流程

tcp 套接字數據傳輸特點

  • tcp連接中當一端退出,另一端如果阻塞在recv,此時recv會立即返回一個空字串。
  • tcp連接中如果一端已經不存在,仍然試圖通過send發送則會產生BrokenPipeError
  • 一個監聽套接字可以同時連接多個客戶端,也能夠重復被連接

網絡收發緩沖區

  • 網絡緩沖區有效的協調了消息的收發速度
  • send和recv實際是向緩沖區發送接收消息,當緩沖區不為空recv就不會阻塞。

tcp粘包

代碼示例:day2/stick_send.py,stick_recv.py

原因:tcp以字節流方式傳輸,沒有消息邊界。多次發送的消息被一次接收,此時就會形成粘包。

影響:如果每次發送內容是一個獨立的含義,需要接收端獨立解析此時粘包會有影響。

處理方法:

  • 人為的添加消息邊界
  • 控制發送速度
 1 from socket import *
 2 
 3 
 4 sockfd = socket()
 5 
 6 server_addr = ("172.40.91.150",8888)
 7 sockfd.connect(server_addr)
 8 
 9 while True:
10   sockfd.send(b'hello')
11 
12 sockfd.close()
tcp 粘包
 1 import socket
 2 
 3 sockfd = socket.socket(socket.AF_INET,
 4                        socket.SOCK_STREAM)
 5 sockfd.bind(('0.0.0.0', 8888))
 6 
 7 sockfd.listen(3)
 8 
 9 while True:
10   print("Waiting for connect ...")
11   connfd, addr = sockfd.accept()
12   print("Connect from", addr)
13 
14   n = 0
15   while n < 10:
16     n += 1
17     data = connfd.recv(5)
18     print(data)
19 
20   connfd.close()  # 斷開連接
21 
22 # 關閉套接字
23 sockfd.close()
tcp粘包問題

練習:將一個文件從客戶端發送到服務端,要求文件類型隨意.
思路:讀取文件--> send發送       recv接收--> write寫入

 1 from socket import *
 2 import time
 3 #    讀取文件--> send發送
 4 s = socket()
 5 s.connect(('127.0.0.1',8888))
 6 
 7 f = open('img.jpg','rb')
 8 
 9 # 讀取內容,將其發送
10 while True:
11   data = f.read(1024)
12   if not data:
13     time.sleep(0.1)
14     s.send(b'##')
15     break
16   s.send(data)
17 
18 time.sleep(0.1)
19 s.send("發送完畢".encode())
20 
21 f.close()
22 s.close()
23 ---------------------------------------------
24 from socket import *
25 
26 s = socket()
27 s.bind(('0.0.0.0',8888))
28 s.listen(3)
29 
30 c,addr = s.accept()
31 print("Connect from",addr)
32 
33 # 以二進制寫入
34 f = open('mm.jpg','wb')
35 
36 #循環接收內容,寫入文件
37 while True:
38 #    recv接收--> write寫入
39   data = c.recv(1024)
40   if data == b'##':
41     break
42   f.write(data)
43 
44 data = c.recv(1024)
45 print(data.decode())
46 
47 f.close()
48 c.close()
49 s.close()
練習

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM