linux總所周知,一切皆文件。因此我們在讀寫文件時覺得fread,recv這些可以隨便用。下面看看有哪些注意事項呢。
因為C庫的文件處理函數較多,處理起來很靈活。所以在處理套接字時可以用fdopen函數把linux下的文件描述符轉為一個C庫的FILE文件指針來進行讀寫操作。
我們知道在recv出錯時會返回-1,但fread的返回值則不是這樣,它不返回-1。fread/fwrite返回讀到的字節數,返回的字節數小于希望讀的字節數,則表明發生了錯誤或者讀到了文件尾。要使用ferror()和feof來判斷究竟發生了什么。
那么對于一個讀的接口應該按下面這個模板來寫,以處理文件讀寫發生的異常情況
int read_data(FILE *fp, int len)
{int total_len = len;int read_len = 0;int rtn_len = 0;char buffer[RECV_BUF] = {0};while(total_len){read_len = MIN(total_len, RECV_BUF);rtn_len = fread(buffer, sizeof(char), read_len, fp);if(rtn_len < read_len) /* 讀到數據小于預期 */{if(ferror(fp)){if(errno == EINTR) /* 信號使讀操作中斷 */{/* 不做處理繼續往下走 */;}else if(errno == EAGAIN || errno == EWOULDBLOCK) /* 發生了超時 */{lprintf(MSG_ERROR, "socket recvice timeout: %dms\n", RCV_SND_TIMEOUT);total_len -= rtn_len;lprintf(MSG_DEBUG, "read len: %d\n", rtn_len);break;}else /* 其他錯誤 */{lprintf(MSG_ERROR, "fread error: %m\n");break;}}else /* 讀到文件尾 */{lprintf(MSG_ERROR, "socket closed by peer\n");total_len -= rtn_len;lprintf(MSG_DEBUG, "read len: %d\n", rtn_len);break;}}// lprintf(MSG_DEBUG, " %s\n", buffer);total_len -= rtn_len;lprintf(MSG_DEBUG, "read len: %d\n", rtn_len);}if(total_len != 0){lprintf(MSG_ERROR, "we need to read %d bytes, but read %d bytes now\n", len, len - total_len);return -1;}
}
從目前的測試來看不可以!例如我在處理http通信時,我想用fgets來解析http的頭,而后面的數據部分則使用recv來讀,測試發現recv收到的數據前面少了一截。這該如何解釋呢?fgets在讀數據時為提高性能,從socket的接收緩沖區一次性讀了很多數據到自己的緩沖區,然后返回給用戶一行數據,下一次讀數據則優先從C庫自己的緩沖區拿數據。但是下一次你用recv來讀數據了,因此它從socket的接收緩沖區讀到的數據就少了一截。
fread本身不支持超時設置,只可以設置阻塞非阻塞。但fread的FILE指針是通過socket轉過來,而socket是可以設置接收發送超時的,所以使用fread接收socket數據時也就具有超時的屬性。但表現和recv超時不太一樣。
例如設置10s超時,我想recv 1000個字節,10s超時后recv會立馬返回-1.而我想fread 1000個字節,你可能會看見在fread這兒不止卡10s,因為fread會盡量讀滿1000個字節再返回。在C庫實現中,如果10s內,能收到數據,就讀到自己緩沖區,然后接著收數據,直到讀滿1000個字節再返回。如果在10s內讀不到數據那么就返回實際讀到的數據,并把錯誤代碼設置為EAGAIN。
所以假如設置10s超時,用fread讀8個字節,而對端每9s發送一個字節,那么fread將卡72s然后成功返回。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态