1. 前言linux
不少朋友在作網絡編程開發的時候可能都遇到這樣的問題,在進行接收二進制流的數據的時候,使用strlen庫函數來獲得編程
二進制數據長度的時候並不許確。爲何呢??首先,使用strlen進行統計長度的爲字符串,並不是二進制流數據,所以在安全
獲取二進制數據流的定長中並不適合。解決的問題必然使用網絡接收函數的返回值來進行判斷,如recv和recvfrom等。服務器
2. 簡單的網絡服務器網絡
Linux中簡單的網絡服務器作起來很簡單,無非就是如下幾個步驟併發
建立網絡套接字(socket) --> 綁定本地套接字到網絡中(bind) --> 設置最大監聽數目(listen) --> 監聽客戶端接入(accept)socket
3. 具體的例子函數
(服務端)spa
1 #include <stdio.h> 2 #include <string.h> 3 #include <errno.h> 4 #include <sys/types.h> 5 #include <sys/socket.h> 6 #include <arpa/inet.h> 7 #include <unistd.h> 8 9 #define WEB_PORT 8080 10 #define MAX_CLIENT 5 11 #define MAX_RECV 1024 12 13 int main(int argc,char *argv[]) 14 { 15 // 1. 建立網絡套接字 16 int sock = socket(AF_INET,SOCK_STREAM,0); 17 if(0 > sock) 18 { 19 fprintf(stderr,"socket: %s\n",strerror(errno)); 20 return -1; 21 } 22 23 // 2. 設置端口當即釋放,能夠當即使用 24 int on = 1; 25 setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); 26 27 // 3. 綁定本地套接字到網絡中 28 struct sockaddr_in localAddr; 29 socklen_t localAddrLen = sizeof(localAddr); 30 31 localAddr.sin_family = AF_INET; 32 localAddr.sin_port = htons(WEB_PORT); 33 localAddr.sin_addr.s_addr = htonl(INADDR_ANY); 34 35 if(0 > bind(sock,(struct sockaddr *)&localAddr,localAddrLen)) 36 { 37 fprintf(stderr,"bind: %s\n",strerror(errno)); 38 return -1; 39 } 40 41 // 4. 設置最大監聽數目 42 if(0 > listen(sock,MAX_CLIENT)) 43 { 44 fprintf(stderr,"bind: %s\n",strerror(errno)); 45 return -1; 46 } 47 48 // 5. 監聽客戶端接入 49 struct sockaddr_in peerAddr; 50 socklen_t peerAddrLen = sizeof(peerAddr); 51 char cRecvDataBuf[MAX_RECV] = {0}; 52 ssize_t sRecvRet = 0; 53 54 while(1) 55 { 56 int connfd = accept(sock,(struct sockaddr *)&peerAddr,&peerAddrLen); 57 if(0 > connfd) 58 { 59 fprintf(stderr,"accept: %s\n",strerror(errno)); 60 return -1; 61 } 62 63 memset(cRecvDataBuf,0,sizeof(cRecvDataBuf)); 64 sRecvRet = recv(connfd,cRecvDataBuf,sizeof(cRecvDataBuf),0); 65 if(0 > sRecvRet) 66 { 67 fprintf(stderr,"recv: %s\n",strerror(errno)); 68 return -1; 69 } 70 71 printf("\n**************************************\n"); 72 printf("sRecvRet = %ld\n",sRecvRet); 73 printf("strlen(cRecvDataBuf) = %lu\n",strlen(cRecvDataBuf)); 74 printf("**************************************\n"); 75 76 printf("\ncRecvDataBuf :\n%s\n\n",cRecvDataBuf); 77 78 close(connfd); 79 } 80 81 close(sock); 82 83 return 0; 84 }
(客戶端)3d
#include <stdio.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <stdlib.h> #include <unistd.h> #define WEB_PORT 8080 int main(int argc,char *argv[]) { // 1. 建立網絡套接字 int sock = socket(AF_INET,SOCK_STREAM,0); if(0 > sock) { fprintf(stderr,"socket: %s\n",strerror(errno)); return -1; } // 2. 設置端口當即釋放,能夠當即使用 int on = 1; setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)); // 3. 設置服務器的地址和連接發送二進制流數據 struct sockaddr_in serverAddr; socklen_t serverAddrLen = sizeof(serverAddr); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(WEB_PORT); serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); if(0 == connect(sock,(struct sockaddr *)&serverAddr,serverAddrLen)) { FILE *pFile = fopen("./linux.bin.ub","rb"); if(NULL != pFile) { // 4. 獲取二進制文件的數據大小 fseek(pFile,0,SEEK_END); long lFileSize = ftell(pFile); rewind(pFile); // 5. 讀取數據併發送 char *pSendBuf = (char *)malloc(lFileSize+1); if(NULL == pSendBuf) { fprintf(stderr,"malloc: %s\n",strerror(errno)); return -1; } memset(pSendBuf,0,lFileSize+1); fread(pSendBuf,lFileSize,1,pFile); fclose(pFile); send(sock,pSendBuf,lFileSize,0); free(pSendBuf); close(sock); } } return 0; }
(二進制流數據 : 9.27 MB (9,728,804 字節) )
4. 比較結果:
首先本人在服務器端只是接受一次的數據,最大長度爲1024字節,那麼如何收到的二進制數據的程度實際上應該爲1024字節(假設網路正常,只接收一次,因爲文件的二進制流數據大小爲9728804字節,因此收到的數據長度爲1024字節),具體的結果以下:
5. 結論:
從結果圖能夠看出,若是使用strlen進行獲取數據的話只有12字節,使用返回值來定長度的話,確實1024字節,這個返回值纔是正確的。因
此,在網絡編程中,建議你們在發送二進制文件流或者在接收二進制文件流的時候,切記不要使用strlen進行定長,不然容易出錯。可是若是發送的是字符串流的數據的話,這倒不是什麼問題,可是爲了系統安全和數據的準確性,使用返回值比strlen更加有優
勢。