立即學習:https://edu.csdn.net/course/play/24458/296241?utm_source=blogtoedu
?1.send和recv底層分析
?
?
1)不管是recv還是send都不是直接接收對方數據或者發送給對方數據,而是對自己的操作系統內存進行操作;
?
2)客戶端與服務端并不是一個send對于一個recv;
?
3)send過程分析(此處以客戶端向服務端發送數據為例):
?
???? #1.客戶端將數據發送給自己的操作系統,即將數據給操作系統內存,這樣就算是結束了send這個命令,而至于怎么將數據發送給服務端由客戶端的操作系統決定;
?
???? #2.send需要經歷的階段:產生數據——將數據copy給客戶端自己的操作系統內存
?
4)recv過程分析(以服務端接收客戶端數據為例)
?
??? #1.服務端首先是等待客戶端的數據,然后接收數據即可
?
??? #2.recv經歷的階段:wait data(耗時較長)——copy data(首先是客戶端的操作系統內存的數據通過網關發送給服務端的操作系統內存,然后再由服務端的程序從自身的操作系統內存中copy data,再進行執行,這就完成recv的過程)
?
2.粘包產生的原因:由TCP協議中的優化算法nagle算法決定的。TCP協議存在的問題,在UDP協議中不會出現這種問題
?
1)產生粘包的條件:數據小且兩次或多次發送數據的間隔小的情況下會產生粘包現象,所以使用TCP協議不是一定會發生粘包,只有滿足條件才會
?
2)在TCP協議中,send是一條一條消息地發送數據,而recv卻可以一次性接收多條消息發送的數據,即接收到的數據是一個整體,因為在時間間隔較短的時間內發送的小數據會在客戶端的操作系統內存中會被合并成一個數據包,再發送給服務端的操作系統內存,因此無法判斷出哪些數據是哪條消息的,TCP時面向流的
?
?
?
?3)TCP是面向流的,為了減少IO傳輸
的次數進而增加傳輸數據的效率,采用了nagle算法,將間隔時間短的小數據合并成一個大的數據塊進行接收處理,然后將處理后的大的數據塊返回給客戶端,而客戶端無法識別出哪些數據是哪條信息的,故產生了粘包!
?
?
4)在客戶端粘包的情況,在客戶端時間間隔短的情況下發送兩次數據,導致客戶端發送的數據產生粘包現象
#客戶端產生粘包的情況'''
客戶端
'''
import socket
phone = socket.socket((socket.AF_INET,socket.SOCK_STREAM))
phone.connect(('127.0.0.1',8080))
phone.send('hello')
phone.send('world')'''
服務端
'''
import socket
phone = socket.socket((socket.AF_INET,socket.SOCK_STREAM))
phone.bind(('127.0.0.1',8080))
conn,client = phone.accept()res1 = conn.recv(1024)
#b'helloworld'
print('第一次接收的數據:',res1)res2 = phone.recv(1024)
#b''
print('第二次接收的數據:',res2)#客戶端不存在粘包的現象,只需要在客戶端的兩次send之間加入一個time.sleep(2)即可,即破壞粘包產生的條件之一:間隔時間短的情況下發送多次數據
?
4)服務端產生粘包現象
#客戶端
......
phone.send('hello'.encode('utf-8'))
time.sleep(5)
phone.send('world'.encode('utf-8'))
......#服務端
......
res1 = conn.recv(1)
#b'h'
print('第一次接收的數據',res1)
time.sleep(6)#服務器端比客戶端多睡一秒鐘,因此上一次的發送的未接收的數據‘ello’會和這次發送的world在服務器端的操作系統內存中合并在一起
res2 = conn.recv(1024)
#b'elloworld'
print('第二次接收的數據:',res2)
注:上述只是便于理解才用time.sleep()來解決粘包,實際上是非常不支持這樣來解決粘包問題