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库函数进行对话的更多相关文章

  1. php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现

    php从数据库中取二进制流文件转换为图片,图片以二进制流存入数据库实现 function data_uri($contents, $mime) { $base64 = base64_encode($c ...

  2. Selenium2学习-036-WebUI自动化实战实例-034-JavaScript 在 Selenium 自动化中的应用实例之六(获取 JS 执行结果返回值)

    Selenium 获取 JavaScript 返回值非常简单,只需要在 js 脚本中将需要返回的数据 return 就可以,然后通过方法返回 js 的执行结果,方法源码如下所示: /** * Get ...

  3. 接收二进制流(ArrayBuffer) ,并且显示二进制流图片

    1.调用接口,返回二进制流数据 var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { && xhr ...

  4. linux编程中接收主函数返回值以及错误码提示

    程序A创建子进程,并调用进程B,根据不调用的不同情况,最后显示结果不同. #include <stdio.h> #include <unistd.h> #include < ...

  5. JSF页面中使用js函数回调后台bean方法并获取返回值的方法

    由于primefaces在国内使用的并不是太多,因此,国内对jsf做系统.详细的介绍的资料很少,即使有一些资料,也仅仅是对国外资料的简单翻译或者是仅仅讲表面现象(皮毛而已),它们的语句甚至还是错误的, ...

  6. linux recv函数返回值分析

    函数原型: ssize_t recv(int sockfd, void *buf, size_t len, int flags); 该函数第一个参数制定接收端套接字描述符; 第二个参数指明一个缓冲区, ...

  7. 解决axios接收二进制流文件乱码问题

    1. 须将axios 配置中的responseType设置为'arraybuffer',这样就不会让表格出现乱码现象: 2. 如果要动态设置文件名则需要让后台将名字设置到响应头中,否则将是一个乱码的文 ...

  8. net9:图片文件转换成二进制流存入SQL数据库,以及从数据库中读取二进制流输出文件

    原文发布时间为:2008-08-10 -- 来源于本人的百度文章 [由搬家工具导入] using System;using System.Data;using System.Configuration ...

  9. 分析案例:应用服务无响应,任务管理器中发现大量w3wp僵尸进程----等待异构系统WebService返回值

    问题描述:       某二次开发的项目反馈,不定期出现应用服务器无响应的情况,登录服务器发现任务管理器中有大量的w3wp僵尸进程. 分析过程: 针对同一进程每隔15秒抓取dump,连续抓取3个,对比 ...

随机推荐

  1. 创建 Rex-Ray volume - 每天5分钟玩转 Docker 容器技术(76)

    前面我们安装部署了 Rex-Ray,并且成功配置 VirtualBox backend,今天演示如何创建和使用 Rex-Ray volume. 在 docker1 或 docker2 上执行如下命令创 ...

  2. 简单说明CGI是什么

    html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...

  3. [Tjoi2013]循环格

    [Tjoi2013]循环格 2014年3月18日1,7500 Description Input 第一行两个整数R,C.表示行和列,接下来R行,每行C个字符LRUD,表示左右上下. Output 一个 ...

  4. .net通用防SQL注入漏洞程序(Global.asax方式)

    原理很简单:使用Global.asax中的Application_BeginRequest(object sender, EventArgs e)事件,实现表单或URL提交数据的获取,然后通过SQLI ...

  5. YYHS-Super Big Stupid Cross(二分+扫描线+平衡树)

    题目描述 “我是超级大沙茶”——Mato_No1 为了证明自己是一个超级大沙茶,Mato 神犇决定展示自己对叉(十字型)有多么的了 解. Mato 神犇有一个平面直角坐标系,上面有一些线段,保证这些线 ...

  6. Ubuntu下的终端多标签切换快捷键

    ubuntu下由于常在终端下工作,也同样需要在一个终端窗口下开启多个标签方便日常开发工作(vim党,尽量避免使用鼠标) 方法一: alt+1 alt+2 alt+3 方法二: ctrl + pageU ...

  7. python修改注册表

    与注册表操作相关的函数可以分为打开注册表.关闭注册表.读取项值.c添加项值.添加项,以及删除项等几类. 表1   Windows注册表基本项 项名 描述 HKEY_CLASSES_ROOT 是HKEY ...

  8. Python系列之内置函数

    内置函数 一.数学运算类: abs(a):求绝对值如果参数是个复数则返回复数的模. a = abs(-1) print(a) >>>1 compilex([real[, imag]] ...

  9. C# Async/await 异步多线程编程

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...

  10. sqlserver游标使用和循环

    /*** 游标的使用 讲了这个多游标的优点,现在我们就亲自来揭开游标的神秘的面纱. 使用游标的顺序: 声名游标.打开游标.读取数据.关闭游标.删除游标. 1.3.1声明游标 最简单游标声明:DECLA ...