日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

盤點python socket 中recv函數(shù)的坑...

 昵稱45893186 2022-11-15 發(fā)布于浙江

1. 首先來看一下recv函數(shù)的各個參數(shù)

函數(shù)原型:int recv( SOCKET s, char *buf, int  len, int flags)

功能:不論是客戶還是服務(wù)器應(yīng)用程序都用recv函數(shù)從TCP連接的另一端接收數(shù)據(jù)。

參數(shù)一:指定接收端套接字描述符;

參數(shù)二:指明一個緩沖區(qū),該緩沖區(qū)用來存放recv函數(shù)接收到的數(shù)據(jù);

參數(shù)三:指明buf的長度;

參數(shù)四 :一般置為0。
 

同步Socket的recv函數(shù)的執(zhí)行流程:當應(yīng)用程序調(diào)用recv函數(shù)時,recv先等待s的發(fā)送緩沖中的數(shù)據(jù)被協(xié)議傳送完畢,

如果協(xié)議在傳送s的發(fā)送緩沖中的數(shù)據(jù)時出現(xiàn)網(wǎng)絡(luò)錯誤,那么recv函數(shù)返回SOCKET_ERROR;

如果s的發(fā)送緩沖中沒有數(shù)據(jù)或者數(shù)據(jù)被協(xié)議成功發(fā)送完畢后,recv先檢查套接字s的接收緩沖區(qū),如果s接收緩沖區(qū)中沒有數(shù)據(jù)或者協(xié)議正在接收數(shù)據(jù),那么recv就一直等待,直到協(xié)議把數(shù)據(jù)接收完畢;

當協(xié)議把數(shù)據(jù)接收完畢,recv函數(shù)就把s的接收緩沖中的數(shù)據(jù)copy到buf中(注意協(xié)議接收到的數(shù)據(jù)可能大于buf的長度,所以在這種情況下要調(diào)用幾次recv函數(shù)才能把s的接收緩沖中的數(shù)據(jù)copy完。recv函數(shù)僅僅是copy數(shù)據(jù),真正的接收數(shù)據(jù)是協(xié)議來完成的),recv函數(shù)返回其實際copy的字節(jié)數(shù);

如果recv在copy時出錯,那么它返回SOCKET_ERROR;如果recv函數(shù)在等待協(xié)議接收數(shù)據(jù)時網(wǎng)絡(luò)中斷了,那么它返回0。
 

2.“坑”在哪里,在返回值上,在阻塞與非阻塞上

要知道,recv函數(shù)是阻塞的,也就是會一直等待服務(wù)端發(fā)送來的數(shù)據(jù)包。如果沒有數(shù)據(jù)包到來,就一直會等待。

這就直接導(dǎo)致了我用python寫服務(wù)端的時候出現(xiàn)的一個解決了很久的錯誤,我的代碼很簡單,就是python服務(wù)端循環(huán)調(diào)用recv函數(shù)接收從客戶端發(fā)來的一個文件,如下:

  1. data = connection.recv(1024)
  2. total_data += data
  3. num = len(data)
  4. # 我一開始以為如果沒有數(shù)據(jù)了,讀出來的data長度為0,len(data)==0,從而導(dǎo)致卡在while循環(huán)中
  5. while len(data) > 0:
  6. data = connection.recv(1024)
  7. num += len(data)
  8. total_data += data

而實際上只有當recv函數(shù)在等待協(xié)議接收數(shù)據(jù)時網(wǎng)絡(luò)中斷了,它才返回0,這就導(dǎo)致我在服務(wù)端一直沒有反應(yīng),等待了很久之后,我將客戶端關(guān)閉之后,出現(xiàn)了結(jié)果,其實就是這時候 len(data)=0 了。

3. 解決方法有哪些呢?

后來搜集資料才發(fā)現(xiàn)recv本身是一個阻塞的,所以可以通過以下兩種方法,將recv設(shè)置為非阻塞:

1. socket.setblocking(0)

2. 使用 socket.MSG_DONTWAIT

注意將套接字設(shè)置為非阻塞時,可能會報一個錯:

WinError 10035 無法立即完成一個非阻止性套接字操作

這個錯誤就是,recv不阻塞了。在 send 數(shù)據(jù)出去后,服務(wù)端還來沒來得急返回數(shù)據(jù),客戶端已經(jīng)跑到了recv這里,而又不阻塞,所以拋出了一個異常。

要解決這個問題,你需要在每個 recv 函數(shù)前加一句 time.sleep(2),

其實還可以通過設(shè)置 socket.settimeout(5)  即超時時間來改變recv的阻塞狀態(tài),間接地將阻塞狀態(tài)變?yōu)榉亲枞麪顟B(tài)。當然,你得確保你的超時時間足夠使recv函數(shù)接收完所有的數(shù)據(jù)才行。

我就是通過設(shè)置超時時間解決了這個問題,你如果也有同樣的問題的話,你也可以試試。

但是設(shè)置超時在實際情況中是一個不是很推薦的方法,后來在對socket原理的了解上更改了代碼,解決了這個問題,服務(wù)端把設(shè)置超時去掉,然后在Android即Java客戶端發(fā)送完所有的數(shù)據(jù)之后,加上如下語句:

this.socket.shutdownOutput();

就可以解決這個服務(wù)端阻塞的問題。

最后遇到問題,一定要去多看看別人是怎么解決的,多和有經(jīng)驗的人交流交流,不然時間就在糾結(jié)苦惱中溜走了。當然,自己首先要進行獨立思考,并將問題一步步放小,找到真正的問題癥結(jié)所在,再去下手。最后如果問題得到解決了,記得分享一下以供更多人參考哦~

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多