tcp/udp下的socket的基本使用
基于tcp的socket
Tcp是基于連結的,必須先啟動服務端,然後啟動用戶端進行連結
服務端:
ss = socket() #建立伺服器套接字
ss.bind() #把位址綁定到套接字
ss.listen() #監聽連結
inf_loop: #伺服器無限循環
cs = ss.accept() #接受用戶端連結
comm_loop: #通訊循環
cs.recv()/cs.send() #對話(接收與發送)
cs.close() #關閉用戶端套接字
ss.close() #關閉伺服器套接字(可選)
用戶端:
cs = socket() #建立客戶套接字
cs.connect() #嘗試連接配接伺服器
comm_loop: #通訊循環
cs.send()/cs.recv() #對話(發送/接收)
cs.close() #關閉客戶套接字
簡單的實作:
這裡是單個的 一次通信
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuQDNwMTO2IDN30iN2MjMxgTM3EDOxUDM4EDMy0yMwgjN5MTMvwVNwgTMwIzLcNDM4YTOzEzLcd2bsJ2Lc12bj5ycn9Gbi52YugTMwIzcldWYtl2Lc9CX6MHc0RHaiojIsJye.png)
mport socket #AF_INET 基于網絡通信, SOCK_STREAM(基于流的,tcp)
phone= socket.socket(socket.AF_INET, socket.SOCK_STREAM) #買手機
phone.bind(('127.0.0.1', 8000)) #綁定手機卡
phone.listen(5) #開機(監聽) # 5表示 最多有5個可以發送連接配接, 放在連結池中
print('--->')
conn, addr= phone.accept() #(等電話,等待連接配接,會阻塞)(觸發的是3次握手)
#收發消息(在tcp協定中觸發的是資料傳輸)#注意收發資訊不是用手機, 而是conn這條連接配接
mesg = conn.recv(1024) #收消息
print('用戶端發來的消息是:',mesg)
conn.send(mesg.upper())#發消息
#斷開連結 (在tcp協定中觸發的是4次揮手)
conn.close()#關機
phone.close()
服務端
importsocket
phone= socket.socket(socket.AF_INET, socket.SOCK_STREAM) #買手機
phone.connect(('127.0.0.1', 8000)) #撥通電話 (觸發的是三次握手)
#收發資料#phone.send('hello'.encode('utf-8')) # socket不支援字元串發送,僅支援位元組編碼發送是以要用
phone.send(bytes('hello', encoding='utf-8')) #這兩個發送一樣,隻要轉換成二進制就行
data = phone.recv(1024)print('收到服務端發來的消息', data)
用戶端
這個是簡單的互動模式
#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-14 下午5:56#@Author : LK#@File : fu_ceshi.py#@Software: PyCharm
from socket import *buffersize= 1024
#tcp_server = socket(AF_INET, SOCK_STREAM) #流式套接字
tcp_server.bind(('127.0.0.1', 8000))
tcp_server.listen(5)#為了接收多個連接配接
whileTrue:#等待連接配接
conn, add = tcp_server.accept() #等待連接配接 ,會阻塞
print('雙向連接配接是:',conn)print('用戶端位址是',add)#收發資訊
whileTrue:#try:
#這個異常實在win中,但是在linux下有時候是死循環, 因為用戶端突然斷掉,conn就沒了,mesg一直是空
mesg =conn.recv(buffersize)if notmesg:print('用戶端你斷開連接配接了')break
print('服務端接收的資訊:',mesg.decode('utf-8'))
conn.send(mesg.upper())print('服務端以發送回去')#except Exception:
#break
conn.close()#關閉連接配接
tcp_server.close()
服務端
from socket import *buffersize=1024tcp_client=socket(AF_INET, SOCK_STREAM)#主動連接配接
tcp_client.connect(('127.0.0.1', 8000))#收發資訊
whileTrue:
send_mesg= input('請輸入要個服務端發送的資訊,break停止').strip('')#如果發送的是空格,重新發送
if not send_mesg: continue
if send_mesg == 'break':print('用戶端停止發送資訊了')break
else:
tcp_client.send(send_mesg.encode('utf-8'))print('用戶端已發送消息')
mesg=tcp_client.recv(buffersize)print('用戶端接受的資訊:',mesg.decode('utf-8'))#關閉連接配接
tcp_client.close()
用戶端
基于udp的socket
udp是無連結的,先啟動哪一端都不會報錯
服務端:
ss= socket() #建立一個伺服器的套接字
ss.bind() #綁定伺服器套接字
inf_loop: #伺服器無限循環
cs = ss.recvfrom()/ss.sendto() #對話(接收與發送)
ss.close() #關閉伺服器套接字
用戶端
cs= socket() #建立客戶套接字
comm_loop: #通訊循環
cs.sendto()/cs.recvfrom() #對話(發送/接收)
cs.close() #關閉客戶套接字
udp基本實作:
#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-15 下午1:38#@Author : LK#@File : udp_服務端.py#@Software: PyCharm
from socket import *ip_port= (('127.0.0.1', 8080))
buffsize= 1024udp_server= socket(AF_INET, SOCK_DGRAM) #資料報套接字
udp_server.bind(ip_port)whileTrue:
data, addr=udp_server.recvfrom(buffsize)print('用戶端發來的消息',data.decode('utf-8'))
udp_server.sendto(data.upper(), addr)#注意這裡是addr
udp_server.close()
udp服務端
#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-15 下午1:38#@Author : LK#@File : udp_用戶端.py#@Software: PyCharm
from socket import *ip_port= (('127.0.0.1', 8080))
buffsize= 1024udp_client= socket(AF_INET, SOCK_DGRAM) #資料包套接字
whileTrue:try:
mesg= input('>>>').strip()
udp_client.sendto(mesg.encode('utf-8'), ip_port)#recvfrom 接受的是一個元祖, 裡面是資訊和對方位址
data, addr =udp_client.recvfrom(buffsize)print('服務端發來的是', data.decode('utf-8'))#print(data)
exceptKeyboardInterrupt as e:print(e)print('程式異常中斷')break
#recv 在自己這端的緩沖區為空時,會阻塞(傳回的是資訊)#recvfrom 不會阻塞 (傳回是一個元祖,分别是接受的資訊和位址)
#tcp沒有實作并發,而udp預設實作了,因為udp不用建立連接配接,直接網端口發送,而tcp需要建立連接配接
udp用戶端
udp的用戶端可以開多個,
常用函數
服務端套接字函數
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粘包問題
首先要知道socket的收發消息的原理
send 是發送給用 對方後,存在對方的核心态中,
recv 收消息是從自己的緩存中收
隻有tcp有粘包現象,udp沒有,但是udp會發生丢包問題, 就是發的資料太多,到那時udp的緩沖區,隻能接收固定大小,剩下的就丢了, 是以udp沒有tcp可靠
流程就是, 服務端發送資料給自己的緩沖區,然後通過網絡發送給用戶端的緩沖區,
用戶端從自己的緩沖區進行取資料,recv函數 一次可能取不完,就可能會出現粘包問題
如果recv取的少的話,或者發送的過多,就可能會出現粘包問題
Recv 是從自己的 核心态中去資料, 如果資料過多的話就會出現粘包問題
解決粘包問題思路: 可以先擷取消息的大小, 然後死循環一直發,知道發送到指定大小在停止, 收包也是如此
所謂粘包問題主要還是因為接收方不知道消息之間的界限,不知道一次性提取多少位元組的資料所造成的。
粘包的表現
#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-16 上午8:42#@Author : LK#@File : tcp_粘包問題_服務端.py#@Software: PyCharm
#粘包問題發生的原因:#第一種情況:tcp在發送的時候,基于流的方式發送資料,發送端要等緩沖區滿後才發送出去,造成粘包#(發送資料的時間很短,資料很小,就會和在一起發送)
#第二種情況,發送端發送的資料很大,但是接收端的緩沖區已經放不下,直接從緩沖區裡面拿#多次都從緩沖區裡面取資料(就是發送的大,但是取的少)
#解決方法:一般是先發送一個資料大小,然後回複一下,在用循環發送資料,進階辦法(struct),跟進階(偏函數)
from socket import *tcp_socket=socket(AF_INET, SOCK_STREAM)
ip_port= (('127.0.0.1', 8080))
tcp_socket.bind(ip_port)
tcp_socket.listen(5)
conn, addr=tcp_socket.accept()print('連接配接的資訊',conn)print('詳細資訊',addr)#收發資料
whileTrue:#'''第二種粘包現象,就是發的多,每次收的少'''
#mesg = conn.recv(2)
#print('第一次接受的',mesg.decode('utf-8'))
#mesg = conn.recv(1)
#print('第二次接受的',mesg.decode('utf-8'))
#mesg = conn.recv(1)
#print('第三次接受的',mesg.decode('utf-8'))
'''第一種粘包現象, 發的少收得多'''mesg= conn.recv(1024)print('第一次接受的',mesg.decode('utf-8'))
mesg= conn.recv(1)print('第二次接受的',mesg.decode('utf-8'))
mesg= conn.recv(1)print('第三次接受的',mesg.decode('utf-8'))
coon.close()
tcp_socket.close()
粘包的表現_服務端
#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-16 上午8:41#@Author : LK#@File : tcp_粘包問題_用戶端.py#@Software: PyCharm
from socket import *tcp_client=socket(AF_INET, SOCK_STREAM)
ip_port= (('127.0.0.1',8080))
tcp_client.connect(ip_port)#收發消息
whileTrue:'''第一中粘包現象,發的少,收的多'''tcp_client.send('第一次發送的'.encode('utf-8'))
tcp_client.send('第二次發送的'.encode('utf-8'))
tcp_client.send('第三次發送的'.encode('utf-8'))
tcp_client.recv(4)#'''第二種粘包現象,發的多收的少'''
#tcp_client.send(b'hhhh')
#tcp_client.send(b'ff')
#tcp_client.recv(4)
粘包的表現_用戶端
圖解模式:
粘包的本質:接收端不知道,從緩存中取多少
第一種粘包現象:
接收端
發送端
運作結果
第二種粘包現象
接收端
發送端
結果
tcp模拟終端,shell執行結果來顯示 粘包問題并解決
如果是linux下 ,不用修改, 輸入ls 顯示目前目錄下的檔案,然後輸入ifconfig 檢視ip等資訊,傳回的資訊比較多,一次不能提取完,再輸入其他指令就會産生錯誤
windows 中 如果産生編碼錯誤就把utf-8 改成gbk
指令用win下的 如 dir 然後 ipconfig 再輸入 其他的
#存在粘包問題
importsubprocessfrom socket import *
from tcp_模拟終端處理資料 importdealwith
ip_port= (('127.0.0.1', 9000))
buffsize= 1024tcp_server=socket(AF_INET, SOCK_STREAM)try:
tcp_server.bind(ip_port)
tcp_server.listen(5)print('還沒有人連接配接')#等待多個連接配接
whileTrue:try:
conn, addr=tcp_server.accept()print('用戶端連接配接資訊', conn)print('用戶端位址', addr)#收發消息
whileTrue:
mesg=conn.recv(buffsize)if notmesg:print('用戶端中斷連接配接了,伺服器等待下次連接配接')break
print('用戶端發送的是', mesg.decode('utf-8'))
data=dealwith(mesg)#将這些封裝成了一個函數
'''# # 處理從用戶端接收的資訊
# # res是接收的資訊,經過shell腳本處理後的結果
# res = subprocess.Popen(mesg.decode('utf-8'), shell=True,
# stdin=subprocess.PIPE,
# stdout=subprocess.PIPE,
# stderr=subprocess.PIPE
# )
# # 擷取錯誤資訊
# err = res.stderr.read().decode('utf-8')
# if not err:
# data = res.stdout.read().decode('utf-8')
# else:
# data = err'''conn.sendall(data)print('服務端已發送')exceptKeyboardInterrupt as e:print('外部強制結束')breakconn.close()exceptOSError as e:print('端口以用過')
tcp_server.close()
模拟終端_産生粘包_服務端
#存在粘包問題
from socket import *tcp_client=socket(AF_INET, SOCK_STREAM)
ip_port= (('127.0.0.1', 9000))
buffsize= 1024tcp_client.connect(ip_port)whileTrue:#mesg = input('>>>').strip()
#去除左右空格
mesg = input('>>>').lstrip().rstrip()if not mesg: continuetcp_client.send(mesg.encode('utf8'))print('用戶端已發送')
data=tcp_client.recv(buffsize)if notdata:print('服務端發來的是空資訊')continue
print('服務端發來的資訊是:',data.decode('utf-8'))
tcp_client.close()
模拟終端_産生粘包_用戶端
#!/usr/bin/env python#-*- coding: utf-8 -*-#@Time : 18-5-15 下午5:23#@Author : LK#@File : tcp_模拟終端處理資料.py#@Software: PyCharm
importsubprocessdefdealwith(mesg):#處理從用戶端接收的資訊
#res是接收的資訊,經過shell腳本處理後的結果
res = subprocess.Popen(mesg.decode('utf-8'), shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)#擷取錯誤資訊
err =res.stderr.read()if noterr:
data=res.stdout.read()if notdata:#data = '你輸入的資料傳回值為空'.encode('utf-8')
return '你輸入的資料傳回值為空'.encode('utf-8')else:
data=errreturndata#這裡傳回的是一個位元組的形式
#res = subprocess.Popen('ls', shell=True,#stdin=subprocess.PIPE,#stdout=subprocess.PIPE,#stderr=subprocess.PIPE#)## stdin=subprocess.PIPE, 标準輸入, 輸入的内容會放在管道中## stdout=subprocess.PIPE, 标準輸出,就是結果會放在pipe這個管道中## stderr=subprocess.PIPE, 标準錯誤,如果結果錯誤 會放在這個管道中#
## 讀取管道内容## print(res.stdout.read()), 讀取之後,管道裡面的就沒有輸出了
資料處理
第一種處理粘包的方法:
思路: 在發送端首先發送給接受端一個4個位元組大小的資料,内容是要發的真是資料的大小.接收端在取資料的時候取4個位元組,
然後給發送端發送一個準備接受的信号,當發送端接收到這個信号時,開始發送資訊.接收端開始循環接收資訊.
struct的用法
importsubprocessfrom socket import *
from tcp_模拟終端處理資料 importdealwith
ip_port= (('127.0.0.1', 9000))
buffsize= 1024tcp_server=socket(AF_INET, SOCK_STREAM)try:
tcp_server.setsockopt(SOL_SOCKET, SO_REUSEPORT,1)
tcp_server.bind(ip_port)
tcp_server.listen(5)print('還沒有人連接配接')#等待多個連接配接
whileTrue:try:
conn, addr=tcp_server.accept()print('用戶端連接配接資訊', conn)print('用戶端位址', addr)#收發消息
whileTrue:
mesg=conn.recv(buffsize)if notmesg:print('用戶端中斷連接配接了,伺服器等待下次連接配接')break
print('用戶端發送的是', mesg.decode('utf-8'))
data=dealwith(mesg)#解決粘包:,發送端先發送一個消息的大小,接收端回複一個準備接收的信号,然後發送端開始循環發送資訊
length =len(data)
conn.send(str(length).encode('utf-8'))
read_send= conn.recv(buffsize).decode('utf-8')#注意這裡的問題,就是發送一個大的檔案,用sendall,,如何發送,還是在于如何取
if read_send == 'read_recv':
conn.sendall(data)print('服務端已發送')exceptKeyboardInterrupt as e:print('外部強制結束')breakconn.close()exceptOSError as e:print('端口以用過')#tcp_server.close()
tcp_server.close()
解決粘包問題_low版_服務端
#low版解決粘包問題
from socket import *
importsys
tcp_client=socket(AF_INET, SOCK_STREAM)
ip_port= (('127.0.0.1', 9000))
buffsize= 1024tcp_client.connect(ip_port)#3 用connect_ex()比較好, 可以重複利用 端口
whileTrue:#去除左右空格
mesg = input('>>>').lstrip().rstrip()if not mesg: continuetcp_client.send(mesg.encode('utf8'))print('用戶端已發送')
data_lenth= int(tcp_client.recv(1024).decode('utf-8'))#解決粘包問題
tcp_client.send('read_recv'.encode('utf-8'))
recv_leng=0
data= b''
while recv_leng buffsize:
data+=tcp_client.recv(buffsize)
recv_leng=len(data)else:#當剩餘的資料 小于緩沖區大小時
data += tcp_client.recv(data_lenth -recv_leng)
recv_leng=len(data)if notdata:print('服務端發來的是空資訊')continue
print('服務端發來的資訊是:', data.decode('utf-8'))
tcp_client.close()
解決粘包問題_low版_用戶端
第二種處理粘包方法:推薦使用
思路struct,發送端用struct.pack() (一般用int類型占4個位元組) 将要發送的資料的大小打包後發送過去,然後在發送真實資料.兩個必然會粘包.
但是接收端在接收的時候先接收4個位元組,然後用struct.unpack()解包,得到資料大小,再利用循環接受真實資料.
struct用法:
http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html
#用struct 解決粘包
importstructimportsubprocessfrom socket import *
from tcp_模拟終端處理資料 importdealwith
ip_port= (('127.0.0.1', 9000))
buffsize= 1024tcp_server=socket(AF_INET, SOCK_STREAM)#這一句是 重複利用 端口
try:
tcp_server.setsockopt(SOL_SOCKET, SO_REUSEPORT,1)
tcp_server.bind(ip_port)
tcp_server.listen(5)print('還沒有人連接配接')#等待多個連接配接
whileTrue:try:
conn, addr=tcp_server.accept()print('用戶端連接配接資訊', conn)print('用戶端位址', addr)#收發消息
whileTrue:
mesg=conn.recv(buffsize)if notmesg:print('用戶端中斷連接配接了,伺服器等待下次連接配接')break
print('用戶端發送的是', mesg.decode('utf-8'))
data=dealwith(mesg)#解決粘包:,發送端先發送一個消息的大小,接收端回複一個準備接收的信号,然後發送端開始循環發送資訊
length =len(data)
conn.send(struct.pack('i', length))
conn.sendall(data)print('服務端已發送')exceptKeyboardInterrupt as e:print('外部強制結束')breakconn.close()exceptOSError as e:print('端口以用過')#tcp_server.close()
tcp_server.close()
解決粘包-服務端_推薦使用
#struct解決粘包
from socket import *
importstruct
tcp_client=socket(AF_INET, SOCK_STREAM)
ip_port= (('127.0.0.1', 9000))
buffsize= 1024tcp_client.connect(ip_port)whileTrue:#mesg = input('>>>').strip()
#去除左右空格
mesg = input('>>>').lstrip().rstrip()if not mesg: continuetcp_client.send(mesg.encode('utf8'))print('用戶端已發送')#解決粘包
#服務端會發送過來一個 資料的大小,和 一個真實資料的包,兩個必定會粘包,但是解包是分開來解,先解4個位元組(對方發來的資料包大小)
data_length = tcp_client.recv(4)
length= struct.unpack('i', data_length)[0]#循環接收資料
recv_leng =0
data= b''
while recv_leng buffsize:
data+=tcp_client.recv(buffsize)
recv_leng=len(data)else:
data+= tcp_client.recv(length-recv_leng)
recv_leng=len(data)if notdata:print('服務端發來的是空資訊')continue
print('服務端發來的資訊是:', data.decode('utf-8'))
tcp_client.close()
解決粘包-用戶端
udp 的丢包問題
# udp傳輸資料是以資料報的方式發送,每次發送都是發送完整的資料,但是接收方接收的可能小于發送放,就會産生丢包
# 因為每次都是發送一個完整的,取時也是取完緩沖區,是以不會發生粘包,但是會發生丢包,意味着,這是不安全的
from socket import *udp_server=socket(AF_INET, SOCK_DGRAM)
ip_port= (('127.0.0.1',8080))
udp_server.bind(ip_port)#收發消息
whileTrue:#這裡的6 出現兩個漢字是因為, 漢字的編碼方式不同(3個位元組,在win中不同)
data, addr = udp_server.recvfrom(6)print('第一次接收的資訊是:',data.decode('utf-8'))
data, addr= udp_server.recvfrom(6)print('第二次接收的資訊是',data.decode('utf-8'))#udp_server.sendto(data,addr)
服務端
from socket import *udp_client=socket(AF_INET, SOCK_DGRAM)
ip_port= (('127.0.0.1', 8080))
buffsize= 1024
whileTrue:
data= '第一次發送的資訊'udp_client.sendto(data.encode('utf-8'), ip_port)
data= '第二次發送的資訊'udp_client.sendto(data.encode('utf-8'), ip_port)
udp_client.recvfrom(10)
用戶端
socket_server實作并發
基于tcp的套接字,關鍵就是兩個循環,一個連結循環,一個通信循環
socketserver子產品中分兩大類:server類(解決連結問題)和request類(解決通信問題)
#這樣就tcp伺服器就能被多個使用者連結了, 用戶端流程不變
classMyServer(socketserver.BaseRequestHandler):defhandle(self):#self.request # 相當于 conn
#self.client_address # 相當于 addr
whileTrue:'''在這裡寫收發消息'''s= socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer) #将上面的類執行個體化一個
s.serve_forever() #一直開啟狀态
tcp_socket_server并發版_服務端
importsocketserverimportstructfrom 封裝處理粘包_拆包 importUnPacket, SendDataclassMyServer(socketserver.BaseRequestHandler):defhandle(self):
self.requestprint('連接配接人的資訊')print('conn是', self.request) #conn
print('addr是', self.client_address) #addr
whileTrue:'''收發消息'''head_data= self.request.recv(4)if not head_data: breakreal_data=UnPacket(head_data, self.request)print('用戶端發來的是:%s用戶端位址是是%s' % (real_data.decode('utf-8'), self.client_address))#回複用戶端,防止粘包
send_data = 'aaaaaaaa'SendData(send_data, self.request)if __name__ == '__main__':#pass
print('還沒有人連接配接')
s= socketserver.ThreadingTCPServer(('127.0.0.1', 8080), MyServer) #多線程
#s = socketserver.ForkingTCPServer(('127.0.0.1', 8080), MyServer) # 多程序win中不行
#伺服器一直開着
s.serve_forever()
用戶端
from socket import *
from 封裝處理粘包_拆包 importUnPacket, SendDataimportstruct
tcp_server=socket(AF_INET, SOCK_STREAM)
ip_port= ('127.0.0.1', 8080)
buffsize= 1024tcp_server.connect_ex(ip_port)whileTrue:'''收發資訊'''mesg= input('>>>').strip()#防止粘包處理函數
SendData(mesg, tcp_server)
mesg= tcp_server.recv(4)if not mesg: breakrecv_data=UnPacket(mesg, tcp_server)print('服務端發送的資訊是',recv_data.decode('utf-8'))
tcp_server.close()
處理粘包的問題,封裝了一下後是:
封裝處理粘包_拆包
importstruct#傳過來包的頭部資訊,和連接配接,傳回接受的資料是一個byte類型
defUnPacket(head_data ,conn):
buffsize= 4
'''解決粘包,需要傳送過資料頭,和連接配接'''real_data_length= struct.unpack('i',head_data)[0]
real_data= b''recv_length=0#這個少了點優化
#while recv_length < real_data_length:
#real_data += conn.recv(1024)
#recv_length = len(real_data)
while recv_length buffsize:
real_data+=conn.recv(buffsize)
recv_length=len(real_data)else:
real_data+= conn.recv(real_data_length-recv_length)
recv_length=len(real_data)returnreal_data#接受要發送的資料,是字元串,和要發送的連結(用戶端發送tcp_server, 服務端發送conn或self.request))
defSendData(real_data,conn):'''發送包,發兩次,'''head_length= struct.pack('i', len(real_data)) #後面是一個整數,是以是四個位元組, 這裡有個優化
conn.send(head_length)
conn.sendall(real_data.encode('utf-8'))print('用戶端發送成功')