学习笔记(11):Python网络编程并发编程-粘包底层原理分析
立即學(xué)習(xí):https://edu.csdn.net/course/play/24458/296241?utm_source=blogtoedu
?1.send和recv底層分析
?
?
1)不管是recv還是send都不是直接接收對(duì)方數(shù)據(jù)或者發(fā)送給對(duì)方數(shù)據(jù),而是對(duì)自己的操作系統(tǒng)內(nèi)存進(jìn)行操作;
?
2)客戶端與服務(wù)端并不是一個(gè)send對(duì)于一個(gè)recv;
?
3)send過(guò)程分析(此處以客戶端向服務(wù)端發(fā)送數(shù)據(jù)為例):
?
???? #1.客戶端將數(shù)據(jù)發(fā)送給自己的操作系統(tǒng),即將數(shù)據(jù)給操作系統(tǒng)內(nèi)存,這樣就算是結(jié)束了send這個(gè)命令,而至于怎么將數(shù)據(jù)發(fā)送給服務(wù)端由客戶端的操作系統(tǒng)決定;
?
???? #2.send需要經(jīng)歷的階段:產(chǎn)生數(shù)據(jù)——將數(shù)據(jù)copy給客戶端自己的操作系統(tǒng)內(nèi)存
?
4)recv過(guò)程分析(以服務(wù)端接收客戶端數(shù)據(jù)為例)
?
??? #1.服務(wù)端首先是等待客戶端的數(shù)據(jù),然后接收數(shù)據(jù)即可
?
??? #2.recv經(jīng)歷的階段:wait data(耗時(shí)較長(zhǎng))——copy data(首先是客戶端的操作系統(tǒng)內(nèi)存的數(shù)據(jù)通過(guò)網(wǎng)關(guān)發(fā)送給服務(wù)端的操作系統(tǒng)內(nèi)存,然后再由服務(wù)端的程序從自身的操作系統(tǒng)內(nèi)存中copy data,再進(jìn)行執(zhí)行,這就完成recv的過(guò)程)
?
2.粘包產(chǎn)生的原因:由TCP協(xié)議中的優(yōu)化算法nagle算法決定的。TCP協(xié)議存在的問(wèn)題,在UDP協(xié)議中不會(huì)出現(xiàn)這種問(wèn)題
?
1)產(chǎn)生粘包的條件:數(shù)據(jù)小且兩次或多次發(fā)送數(shù)據(jù)的間隔小的情況下會(huì)產(chǎn)生粘包現(xiàn)象,所以使用TCP協(xié)議不是一定會(huì)發(fā)生粘包,只有滿足條件才會(huì)
?
2)在TCP協(xié)議中,send是一條一條消息地發(fā)送數(shù)據(jù),而recv卻可以一次性接收多條消息發(fā)送的數(shù)據(jù),即接收到的數(shù)據(jù)是一個(gè)整體,因?yàn)樵跁r(shí)間間隔較短的時(shí)間內(nèi)發(fā)送的小數(shù)據(jù)會(huì)在客戶端的操作系統(tǒng)內(nèi)存中會(huì)被合并成一個(gè)數(shù)據(jù)包,再發(fā)送給服務(wù)端的操作系統(tǒng)內(nèi)存,因此無(wú)法判斷出哪些數(shù)據(jù)是哪條消息的,TCP時(shí)面向流的
?
?
?
?3)TCP是面向流的,為了減少IO傳輸
的次數(shù)進(jìn)而增加傳輸數(shù)據(jù)的效率,采用了nagle算法,將間隔時(shí)間短的小數(shù)據(jù)合并成一個(gè)大的數(shù)據(jù)塊進(jìn)行接收處理,然后將處理后的大的數(shù)據(jù)塊返回給客戶端,而客戶端無(wú)法識(shí)別出哪些數(shù)據(jù)是哪條信息的,故產(chǎn)生了粘包!
?
?
4)在客戶端粘包的情況,在客戶端時(shí)間間隔短的情況下發(fā)送兩次數(shù)據(jù),導(dǎo)致客戶端發(fā)送的數(shù)據(jù)產(chǎn)生粘包現(xiàn)象
#客戶端產(chǎn)生粘包的情況''' 客戶端 ''' import socket phone = socket.socket((socket.AF_INET,socket.SOCK_STREAM)) phone.connect(('127.0.0.1',8080)) phone.send('hello') phone.send('world')''' 服務(wù)端 ''' 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('第一次接收的數(shù)據(jù):',res1)res2 = phone.recv(1024) #b'' print('第二次接收的數(shù)據(jù):',res2)#客戶端不存在粘包的現(xiàn)象,只需要在客戶端的兩次send之間加入一個(gè)time.sleep(2)即可,即破壞粘包產(chǎn)生的條件之一:間隔時(shí)間短的情況下發(fā)送多次數(shù)據(jù)?
4)服務(wù)端產(chǎn)生粘包現(xiàn)象
#客戶端 ...... phone.send('hello'.encode('utf-8')) time.sleep(5) phone.send('world'.encode('utf-8')) ......#服務(wù)端 ...... res1 = conn.recv(1) #b'h' print('第一次接收的數(shù)據(jù)',res1) time.sleep(6)#服務(wù)器端比客戶端多睡一秒鐘,因此上一次的發(fā)送的未接收的數(shù)據(jù)‘ello’會(huì)和這次發(fā)送的world在服務(wù)器端的操作系統(tǒng)內(nèi)存中合并在一起 res2 = conn.recv(1024) #b'elloworld' print('第二次接收的數(shù)據(jù):',res2)注:上述只是便于理解才用time.sleep()來(lái)解決粘包,實(shí)際上是非常不支持這樣來(lái)解決粘包問(wèn)題
總結(jié)
以上是生活随笔為你收集整理的学习笔记(11):Python网络编程并发编程-粘包底层原理分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Nginx----OpenResty
- 下一篇: 学习笔记(12):Python网络编程并