Linux网络中接收 "二进制" 流的那些事 --- 就recv的返回值和strlen库函数进行对话
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,);
if( > sock)
{
fprintf(stderr,"socket: %s\n",strerror(errno));
return -;
} // 2. 设置端口立即释放,可以立即使用
int on = ;
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( > bind(sock,(struct sockaddr *)&localAddr,localAddrLen))
{
fprintf(stderr,"bind: %s\n",strerror(errno));
return -;
} // 4. 设置最大监听数目
if( > listen(sock,MAX_CLIENT))
{
fprintf(stderr,"bind: %s\n",strerror(errno));
return -;
} // 5. 监听客户端接入
struct sockaddr_in peerAddr;
socklen_t peerAddrLen = sizeof(peerAddr);
char cRecvDataBuf[MAX_RECV] = {};
ssize_t sRecvRet = ; while()
{
int connfd = accept(sock,(struct sockaddr *)&peerAddr,&peerAddrLen);
if( > connfd)
{
fprintf(stderr,"accept: %s\n",strerror(errno));
return -;
} memset(cRecvDataBuf,,sizeof(cRecvDataBuf));
sRecvRet = recv(connfd,cRecvDataBuf,sizeof(cRecvDataBuf),);
if( > sRecvRet)
{
fprintf(stderr,"recv: %s\n",strerror(errno));
return -;
} 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 ;
}
(客户端)
#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,);
if( > sock)
{
fprintf(stderr,"socket: %s\n",strerror(errno));
return -;
} // 2. 设置端口立即释放,可以立即使用
int on = ;
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( == connect(sock,(struct sockaddr *)&serverAddr,serverAddrLen))
{ FILE *pFile = fopen("./linux.bin.ub","rb");
if(NULL != pFile)
{
// 4. 获取二进制文件的数据大小
fseek(pFile,,SEEK_END);
long lFileSize = ftell(pFile);
rewind(pFile); // 5. 读取数据并发送
char *pSendBuf = (char *)malloc(lFileSize+);
if(NULL == pSendBuf)
{
fprintf(stderr,"malloc: %s\n",strerror(errno));
return -;
} memset(pSendBuf,,lFileSize+);
fread(pSendBuf,lFileSize,,pFile);
fclose(pFile); send(sock,pSendBuf,lFileSize,); free(pSendBuf);
close(sock);
} } return ; }
(二进制流数据 : 9.27 MB (9,728,804 字节) )

4. 比较结果:
首先本人在服务器端只是接受一次的数据,最大长度为1024字节,那么如何收到的二进制数据的程度实际上应该为1024字节(假设网路正常,只接收一次,由于文件的二进制流数据大小为9728804字节,所以收到的数据长度为1024字节),具体的结果如下:

5. 结论:
从结果图可以看出,如果使用strlen进行获取数据的话只有12字节,使用返回值来定长度的话,确实1024字节,这个返回值才是正确的。因
此,在网络编程中,建议大家在发送二进制文件流或者在接收二进制文件流的时候,切记不要使用strlen进行定长,否则容易出错。但是如果发送的是字符串流的数据的话,这倒不是什么问题,但是为了系统安全和数据的准确性,使用返回值比strlen更加有优
势。
Linux网络中接收 "二进制" 流的那些事 --- 就recv的返回值和strlen库函数进行对话的更多相关文章
- php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现
php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现 function data_uri($contents, $mime) { $base64 = base64_encode($c ...
- Selenium2学习-036-WebUI自动化实战实例-034-JavaScript 在 Selenium 自动化中的应用实例之六(获取 JS 执行结果返回值)
Selenium 获取 JavaScript 返回值非常简单,只需要在 js 脚本中将需要返回的数据 return 就可以,然后通过方法返回 js 的执行结果,方法源码如下所示: /** * Get ...
- 接收二进制流(ArrayBuffer) ,并且显示二进制流图片
1.调用接口,返回二进制流数据 var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { && xhr ...
- linux编程中接收主函数返回值以及错误码提示
程序A创建子进程,并调用进程B,根据不调用的不同情况,最后显示结果不同. #include <stdio.h> #include <unistd.h> #include < ...
- JSF页面中使用js函数回调后台bean方法并获取返回值的方法
由于primefaces在国内使用的并不是太多,因此,国内对jsf做系统.详细的介绍的资料很少,即使有一些资料,也仅仅是对国外资料的简单翻译或者是仅仅讲表面现象(皮毛而已),它们的语句甚至还是错误的, ...
- linux recv函数返回值分析
函数原型: ssize_t recv(int sockfd, void *buf, size_t len, int flags); 该函数第一个参数制定接收端套接字描述符; 第二个参数指明一个缓冲区, ...
- 解决axios接收二进制流文件乱码问题
1. 须将axios 配置中的responseType设置为'arraybuffer',这样就不会让表格出现乱码现象: 2. 如果要动态设置文件名则需要让后台将名字设置到响应头中,否则将是一个乱码的文 ...
- net9:图片文件转换成二进制流存入SQL数据库,以及从数据库中读取二进制流输出文件
原文发布时间为:2008-08-10 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...
- 分析案例:应用服务无响应,任务管理器中发现大量w3wp僵尸进程----等待异构系统WebService返回值
问题描述: 某二次开发的项目反馈,不定期出现应用服务器无响应的情况,登录服务器发现任务管理器中有大量的w3wp僵尸进程. 分析过程: 针对同一进程每隔15秒抓取dump,连续抓取3个,对比 ...
随机推荐
- 【bzoj2761】[JLOI2011]不重复数字
给出N个数,要求把其中重复的去掉,只保留第一次出现的数. 例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4. Inpu ...
- Day1 Python基础学习
一.编程语言分类 1.简介 机器语言:站在计算机的角度,说计算机能听懂的语言,那就是直接用二进制编程,直接操作硬件 汇编语言:站在计算机的角度,简写的英文标识符取代二进制去编写程序,本质仍然是直接操作 ...
- SQL server学习(三)T-SQL编程、逻辑控制语句和安全模式
T-SQL编程 T-SQL编程与C语言类似,只是语法稍有不同而已,总体思想还是没有变化的.多的就不说了,还是从变量开始. 变量也分为全局变量和局部变量,表示方式稍有不同. 局部变量: 局部变量必须以标 ...
- Vim的基本使用(二)
本文为原创文章,转载请标明出处 目录 11.可视模式 12.指定计数 13.重复命令 14.外部命令 15.命令行编辑 16.文件编辑 17.分割窗口 18.GUI命令 19.配置 20.Vim Ch ...
- php soap实现WebService接口
nusoap是php写的一个功能文件,下载地址:http://pan.baidu.com/s/1i3mUQJr 一.不使用wsdl服务端 server.php <?php //包函nusoap. ...
- 窗口迅速关闭的解决办法/scanf/if/for/break
break if的格式 if(a>b) { printf("max=%d\n",a); } else printf("max=%d\n",b); scan ...
- win10 uwp 分治法
其实我想说Path,因为最近在做一个简单的分治. 算法涉及到了一个平面几何的知识.就是三角形p1p2p3的面积等于以下行列式的二分之一: 而且当点P3 在射线P1P2的左侧的时候,表达式为正,右侧表达 ...
- 什么是git?window下安装git
一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以 ...
- java四大会话技术
未经作者允许,不得转载 第一cookie技术 常用方法: new Cookie(),构造一个cookie getName() ,获取cookie的名字 getValue () ,取到具体cookie的 ...
- Java 多线程的一些问题
1.volatile关键字的作用 一个非常重要的问题,是每个学习.应用多线程的Java程序员都必须掌握的.理解volatile关键字的作用的前提是要理解Java内存模型,volatile关键字的作用主 ...