|
1. 前言
很多朋友在做网络编程开发的时候可能都遇到这样的问题,在进行接收二进制流的数据的时候,使用strlen库函数来得到
二进制数据长度的时候并不准确。为什么呢??首先,使用strlen进行统计长度的为字符串,并非二进制流数据,因此在
获取二进制数据流的定长中并不适合。解决的问题必然使用网络接收函数的返回值来进行判断,如recv和recvfrom等。
2. 简单的网络服务器
Linux中简单的网络服务器做起来很简单,无非就是以下几个步骤
创建网络套接字(socket) --> 绑定本地套接字到网络中(bind) --> 设置最大监听数目(listen) --> 监听客户端接入(accept)
3. 具体的例子
(服务端)
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#define WEB_PORT 8080
#define MAX_CLIENT 5
#define MAX_RECV 1024
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 localAddr;
socklen_t localAddrLen = sizeof(localAddr);
localAddr.sin_family = AF_INET;
localAddr.sin_port = htons(WEB_PORT);
localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if(0 > bind(sock,(struct sockaddr *)&localAddr,localAddrLen))
{
fprintf(stderr,"bind: %s\n",strerror(errno));
return -1;
}
// 4. 设置最大监听数目
if(0 > listen(sock,MAX_CLIENT))
{
fprintf(stderr,"bind: %s\n",strerror(errno));
return -1;
}
// 5. 监听客户端接入
struct sockaddr_in peerAddr;
socklen_t peerAddrLen = sizeof(peerAddr);
char cRecvDataBuf[MAX_RECV] = {0};
ssize_t sRecvRet = 0;
while(1)
{
int connfd = accept(sock,(struct sockaddr *)&peerAddr,&peerAddrLen);
if(0 > connfd)
{
fprintf(stderr,"accept: %s\n",strerror(errno));
return -1;
}
memset(cRecvDataBuf,0,sizeof(cRecvDataBuf));
sRecvRet = recv(connfd,cRecvDataBuf,sizeof(cRecvDataBuf),0);
if(0 > sRecvRet)
{
fprintf(stderr,"recv: %s\n",strerror(errno));
return -1;
}
printf("\n**************************************\n");
printf("sRecvRet = %ld\n",sRecvRet);
printf("strlen(cRecvDataBuf) = %lu\n",strlen(cRecvDataBuf));
printf("**************************************\n");
printf("\ncRecvDataBuf :\n%s\n\n",cRecvDataBuf);
close(connfd);
}
close(sock);
return 0;
}
(客户端)
#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更加有优
势。 |
|