day 29
半連接與粘包問題
半連接數
1、定義:
三次握手沒有完成的稱之為半連接數
2、產生半連接的原因:
1)惡意客戶端故意不返回第三次握手信息,服務器就處于time_wait狀態
洪水攻擊用的就是這種原理
2)服務器沒有時間處理你的握手請求
3、最大半連接數
在socket語法中listen()函數的括號中指定的就是最大半連接數
最大半連接數指的是同一時間接收請求的最大數目,超過的請求會被直接拒絕
粘包問題
粘包問題只存在于TCP協議中,TCP協議又稱為流式協議,數據之間是沒有分隔的(只能用數據的長度來分隔他們)
1、粘包的定義
如果一次讀取指定緩存區的內容大于或者小于真實數據的大小,就被定義被粘包
2、粘包產生的原因
發送端和接收端都會造成數據的粘包問題
--發送端
1)發送的數據小,并且時間間隔短時,tcp會根據negal優化算法把這兩個數據一起發送,會粘
--接收端
1)接收端一次性讀取了兩次的數據內容,會粘
2)接收端一次沒有把數據接收完整,剩余內容和下次發送的也會粘在一起
3、粘包的解決方案
無論時哪種情況,其根本的原因都在于接收端不知道應該接收多少數據,所以解決的方案就是先把數據長度發給接收端
--發送端
1)使用struct將真實數據的長度轉換成固定的字節數據
2)發送長度數據
3)發送真實數據
import socket import struct client = socket.socket() client.connect(('127.0.0.1',8080))while True:data = '巴拉巴拉一大堆數據'.encode('utf-8')data_len = struct.pack('q',len(data)) # 把數據長度轉成固定字節數client.send(data_len) # 先發送固定字節數 'q'模式的字節數是8client.send(data) # 再發送真實的數據--接收端
1)先收長度數據? 字節數固定
2)再收真實數據 ,真實可能很長,需要循環接收
import socket import struct server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen()while True:client,addr = server.accept()while True:data_len_bytes = client.recv(8) # 先接收傳過來的數據長度信息的固定字節'q'模式是8if not data_len_bytes:breakdata_len = struct.unpack('q',data_len_bytes)[0] # 把接收到的二進制轉成數據的長度,返回一個元組,取0號位data = client.recv(data_len) # 再根據長度來接收數據(循環接收請看前面)?
自定義報頭
1、需要原因
有時候我們除了需要把數據的長度告訴接收方,還需要把一些其他信息也告訴接收方,例如我們下載文件,
服務器就需要把文件名也給我們傳過來,這樣就需要我們自定義報頭
2、報頭形式
當我們想把數據的其他信息傳給對面的時候,字典是我們最好的選擇
對面和你的平臺可能不一樣,這樣我們就需要json格式來傳輸數據,所以報頭的本質就是json數據
想把json數據發過去,又需要先把json數據的長度發過去,真實數據的信息都保存在json數據中
3、有了報頭之后的發送流程
--發送端
1)發送報頭長度
2)發送報頭數據? ?其中包含了真實文件的長度和其他的任意額外信息
3)發送真實文件內容
import socket,struct,json client = socket.socket() client.connect(('127.0.0.1',8080))while True:data = "我是一個很大的文件,并且對面要根據我的名字保存"# 先寫出報頭信息head_info = {"name":"xxx","size":10000}# 把報頭信息轉換成json格式json_head = json.dumps(head_info)# 把json格式的報頭信息的二進制長度轉換成固定字節json_head_lens = struct.pack('q',len(json_head.encode('utf-8')))# 發送固定字節,讓多方知道該以多少長度接收報頭信息client.send(json_head_lens)# 發送報頭信息,里面包含接下來要發送的真實數據的大小以及名字等等client.send(json_head.encode('utf-8'))# 發送真實數據client.send(data.encode('utf-8'))--接收端
1)接收報頭長度
2)接收報頭信息
3)接收文件內容
import socket import struct import json server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen()while True:client,addr = server.accept()while True:head_len_bytes = client.recv(8)# 先把固定字節數的報頭長度接收過來if not head_len_bytes:breakhead_len = struct.unpack('q',head_len_bytes)[0]# 轉換成報頭的長度數據json_str = client.recv(head_len).decode('utf-8')# 接收報頭的信息,傳過來的是json格式head_info = json.loads(json_str)# 轉成字典格式,方便取值#head_info = {"name":"xxx","size":10000}file_size = head_info.get("size")# 從字典中取出真實文件的大小,根據大小取值,循環取值請看之前的data = client.recv(file_size)轉載于:https://www.cnblogs.com/huikejie/p/10966090.html
總結
- 上一篇: Qt在控制台输出中文的解决办法(转载)
- 下一篇: Android 调整屏幕分辩率