TCP传输大文件(图片、文档)

2023-05-16

遇到TCP传输大文件问题,主要是

(1)、传输快,但拼接成的大文件数据错

(2)、加校验,传输变慢

(3)、接收包数跟发送包数不对应

费了一段时间才解决。

今天,整理一下,留以后备用。

首先,TCP是有连接、自带校验的传输协议,不需要再另外加代码(如接收端回复码给发送端)确保其正确性,这样可以保证TCP的速度,基本能达到4M/s以上。


如接收包数和发送包数不一致,这只是说两边发送、接收的速度不对应,发送慢、接受快了,就会出现接收的次数多(不信你可以找找,你接收的数据个数中肯定有小于BUFFER_SIZE的)。所以在拼接成大文件时,就不能按照预设的size进行,应该按照实际接收到的数据size进行偏移。


TCP传输时,发送端和接收端有缓冲区,send()和recv()函数其实只是实现copy功能,把缓冲区的内容拷出来。所以会出现缓冲区爆掉、接收接不全数据的情况。


附上自己调试时写的小代码,仅供参考

客户端实现的功能是,把一段1344000的数据(bmp图片的数据大小去掉54字节的header)发送给服务器端。文件流获取图片数据去图片头,模拟拍照等获取到的纯图片数据。实际传输的数据为1344000的数据。

client.c

#include <netinet/in.h>
#include <sys/types.h>    
#include <sys/socket.h>    
#include <stdio.h>        
#include <stdlib.h>       
#include <string.h>      
#include <time.h>                
#include <arpa/inet.h>


#define SERVER_PORT 6666
#define BUFFER_SIZE 1024


struct image_data{
int value;
unsigned char * imageData;
int length;
struct image_data * next;
};




int main(int argc,char **argv)
{
 if(argc!=2)
  {
      printf("参数错误,清输入两个参数\n");
     exit(1);
   }
  FILE *stream;
  struct sockaddr_in server_addr;
   bzero(&server_addr,sizeof(server_addr)); 
   server_addr.sin_family = AF_INET;    //internet协议族
   server_addr.sin_addr.s_addr = inet_addr(argv[1]);
   server_addr.sin_port = htons(SERVER_PORT);   
   int sfd;
   sfd=socket(AF_INET,SOCK_STREAM,0);
   if(sfd<0)
    {
      printf("socket error\n");
      exit(0);
    }
 
 
        int file_length;
int tcpnum;
int file_send_len;
unsigned char snddata[1344000];
unsigned char buffer[BUFFER_SIZE];
file_length = sizeof(snddata);
FILE *fp;
    if (!(fp = fopen("1.bmp", "rb")))
    {
return -1;
}
fseek(fp, SEEK_SET, 54);
    fread(snddata, sizeof(unsigned char), file_length, fp);
fclose(fp);
struct image_data * temp_data = NULL;
temp_data = (struct image_data *)malloc(sizeof(struct image_data));
temp_data->imageData = (unsigned char *)malloc(sizeof(unsigned char) * file_length);
temp_data ->imageData = snddata;
temp_data ->length = file_length;
 
 
   if(connect(sfd,(struct sockaddr*)&server_addr,sizeof(server_addr)) < 0)
    {
        printf("Can Not Connect To %s\n",argv[1]);
        exit(1);
    }


    bzero(buffer,BUFFER_SIZE);
    printf("正在传输...\n");
    int len=0;
    //不断读取并发送数据


tcpnum = file_length/BUFFER_SIZE;
if((tcpnum * BUFFER_SIZE) < file_length)
{
tcpnum++;
}
printf("tcpnum = %d\n", tcpnum);
int i;
for(i = 0 ; i < tcpnum; i++)
{

if((file_length - i * BUFFER_SIZE) >= BUFFER_SIZE)
{
file_send_len = BUFFER_SIZE;
}
else
{
file_send_len = file_length - i * BUFFER_SIZE;
}
bzero(buffer,BUFFER_SIZE);
memcpy(buffer, temp_data->imageData + (i * BUFFER_SIZE), file_send_len);

len  = send(sfd, buffer, file_send_len, 0);
if(len < 0)
{
printf("send file error\n");
break;
}
}
close(sfd);
printf("tcp over\n");


    return 0;
}




server.c

服务器端把数据存进一个数据,接收完之后,生成bmp图片。还可以直接存进文件(被注释了),但必须在客户端把图片header加上,一起发给服务器端。

#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define SERVER_PORT 6666
#define LISTEN_QUEUE 20
#define BUFFER_SIZE 1024


typedef struct tagRGBQUAD
{
    unsigned char rgbBlue;
    unsigned char rgbGreen;
    unsigned char rgbRed;
} RGBQUAD;
static int youwritetobmp1(RGBQUAD*pixarr, int xsize, int ysize, int num) ;
int num = 0;


int main(int argc,char **argv)
{
  struct sockaddr_in server_addr;
  bzero(&server_addr,sizeof(server_addr));//全部置零
  //设置地址相关的属性
  server_addr.sin_family=AF_INET;
  server_addr.sin_addr.s_addr=htons(INADDR_ANY);
  server_addr.sin_port=htons(SERVER_PORT);




  //创建套接字
  int server_socket=socket(AF_INET,SOCK_STREAM,0);
  if(server_socket<0) 
   {
     printf("socket create error\n");
     exit(1);
   }
  //绑定端口
  if(bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
    {
      printf("bind error\n");
      exit(1);
    }
  //服务器端监听
   if(listen(server_socket,LISTEN_QUEUE))
    {
      printf("Server listen error\n");
      exit(1);
    }


  //服务器端一直运行
  while(1)
   {
     pid_t pid;
     struct sockaddr_in client_addr;
     socklen_t length=sizeof(client_addr);
     //accept返回一个新的套接字与客户端进行通信
     int new_server_socket=accept(server_socket,(struct sockaddr*)&client_addr,&length);
//1*begin******************************************************************************
     if(new_server_socket==-1)
      {
        printf("accept error\n");
        continue;
      }
     else
      {
        printf("客户端%s连接成功\n",inet_ntoa(client_addr.sin_addr));
        pid=fork();
 //3*begin**运行子进程*************************************************************
        if(pid==0)
         {
           int data_len,flag=0;
           char buffer[BUFFER_SIZE];
           // 定义文件流
           FILE *stream;
           bzero(buffer,BUFFER_SIZE);
           strcpy(buffer,"Please enter the total path");
           strcat(buffer,"\n");
           send(new_server_socket,buffer,BUFFER_SIZE,0);
           bzero(buffer,BUFFER_SIZE);
//2*begin**服务器接受数据*********************************************           
          // if((stream=fopen("data","w"))==NULL)
          //  {
          //    printf("file open error\n");
          //    exit(1);
          //  }
          // else
          //  {
          //    bzero(buffer,BUFFER_SIZE);
          //  }


unsigned char recv_data[1344000];
int offset = 0;
bzero(recv_data, 1344000);

          // printf("正在接收来自%s的文件....\n",inet_ntoa(client_addr.sin_addr));
           //先将数据接受到缓冲区buffer中,再写入到新建的文件中
           while((data_len=recv(new_server_socket,buffer,BUFFER_SIZE,0)) > 0)
            {
               flag++;
  printf("flag is %d\n",flag);
  printf("data_len is %d\n",data_len);
               if(flag==1)
                {
                 printf("正在接收来自%s的文件....\n",inet_ntoa(client_addr.sin_addr));
                
                }
            
              if(data_len<0)
               {
                printf("接收错误\n");
                exit(1);
               }
              //向文件中写入数据
              //int write_len=fwrite(buffer,sizeof(char),data_len,stream);
              //if(write_len>data_len)
              // {
              //   printf("file write failed\n");
              //   exit(1);
              // }
      printf("offset is %d\n",offset);
      memcpy(recv_data + offset, buffer, data_len);
              offset +=  data_len;
              bzero(buffer,BUFFER_SIZE);
            }
          if(flag>0)
             printf("%s的文件传送完毕\n",inet_ntoa(client_addr.sin_addr));
           if(flag==0)
             printf("%s的文件传输失败\n",inet_ntoa(client_addr.sin_addr));
//2*end**服务器接受数据**************************************************** 
         // rename("data",inet_ntoa(client_addr.sin_addr)); 
          //fclose(stream);
          //rename("data",inet_ntoa(client_addr.sin_addr));
          
 printf("to bmp file\n");
          youwritetobmp1((RGBQUAD *) recv_data, 1280, 350, num);
 num++;
          exit(1);         
         }
//3*end**运行子进程**********************************************************
        else
         {
           close(new_server_socket);
         }
      }
//1*end**************************************************************************************
   close(new_server_socket);
   }
 return 0;
}



/**描述:生成bmp图片

**参数:1、图片数据  2、宽   3、长  4、保存图片区分字符

*返回:0 成功  -1  不成功

**/
static int youwritetobmp1(RGBQUAD*pixarr, int xsize, int ysize, int num) 
{
       unsigned char header[54] = 
{
        0x42, 0x4d, 0, 0, 0, 0, 0, 
          0, 0, 0,54, 0, 0, 0, 40, 0, 
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
          1, 0, 24, 0,0, 0, 0, 0, 0, 0, 
          0, 0, 0, 0,0, 0, 0, 0, 0, 0,  
          0, 0, 0, 0,0, 0, 0, 0
      };

      RGBQUAD * pixarr1;  
      int i;
      int j;
      long file_size = (long)xsize * (long)ysize * 3 + 54;
      header[2] = (unsigned char)(file_size &0x000000ff);
      header[3] = (file_size >> 8)   & 0x000000ff;
      header[4] = (file_size >> 16) & 0x000000ff;
      header[5] = (file_size >> 24) & 0x000000ff;
    
      long width;
      if(!(xsize%4))     width=xsize;
      else                    width= xsize+(4-xsize%4);     //Èç²»ÊÇ4µÄ±¶Êý£¬Ôòת»»³É4µÄ±¶Êý
      header[18] = width & 0x000000ff;
      header[19] = (width >> 8) &0x000000ff;
      header[20] = (width >> 16) &0x000000ff;
      header[21] = (width >> 24) &0x000000ff;
    
      long height = ysize;
      header[22] = height &0x000000ff;
      header[23] = (height >> 8) &0x000000ff;
      header[24] = (height >> 16) &0x000000ff;
      header[25] = (height >> 24) &0x000000ff;


      char fname_bmp[128];
      sprintf(fname_bmp, "capture_%d.bmp",num);
    
      FILE *fp;
      if (!(fp = fopen(fname_bmp, "wb"))) 
      return -1;
      
      fwrite(header, sizeof(unsigned char), 54, fp);


      RGBQUAD zero={0,0,0};   //²»×ã×֜ڣ¬ÓÃzeroÌî³ä
      pixarr1 = pixarr + xsize * (ysize -1);

      for(j=0;j<ysize;j++)
{
          if(!(xsize%4))
{
              for(i=0;i<xsize;i++)
   
                  fwrite(pixarr1+i, sizeof(RGBQUAD),1, fp);
              }
      pixarr1 -=xsize;  
          }
          else
          {
              for(i=0;i<xsize;i++)

                  fwrite(pixarr+i, sizeof(RGBQUAD),1, fp);
              }

              for(i=xsize;i<xsize+(4-xsize%4);i++)
{
                  fwrite(&zero, sizeof(RGBQUAD),1, fp);
              }
          }
     }
    
     fclose(fp);
     return 0;


}


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TCP传输大文件(图片、文档) 的相关文章

  • 用 C 处理 TCP 的部分返回

    我一直在读Beej 的网络编程指南 http beej us guide bgnet 获取 TCP 连接的句柄 在其中一个示例中 简单 TCP 流客户端的客户端代码如下所示 if numbytes recv sockfd buf MAXDA
  • Linux Socket write() 的错误文件描述符 错误的文件描述符 C

    我对 write 2 函数有一个有趣的问题 PrepareResponseForSetCoordinates 函数会导致写入时出现错误的文件描述符错误 这是错误行 perror 写入套接字时出错 总产量 写入套接字时出错 文件描述符错误 我
  • Nodejs TCP连接客户端端口分配

    我使用nodejs在客户端和服务器之间创建了tcp连接 网络模块 https nodejs org api net html 服务器正在侦听已经预定义的端口 并且客户端正在连接到该端口 据我了解客户端的端口是由节点动态分配的 那是对的吗 节
  • TCP 代理:在后端不可用时保持连接

    在 Docker 设置的上下文中 我想使用类似大使的模式来允许某些容器 例如数据库服务器 正常重新启动 而不必重新启动所有依赖的容器 例如 Web 服务器 并且没有错误消息 因为 数据库服务器不可用 因此 我想知道 是否有一个 TCP 代理
  • 很难理解带有 async_read 和 async_write 的 Boost ASIO TCP 的一些概念

    我很难理解使用 async read 和 async write 时构建 tcp 客户端的正确方法 这examples http www boost org doc libs 1 38 0 doc html boost asio examp
  • 是什么导致 MSSQL 中出现“非阻塞套接字上的操作将阻塞”错误?

    错误 异常查询为 CREATE NONCLUSTERED INDEX I1 ON AllAccounts BAK Master received Day ASC 出现异常 发生一个或多个错误 错误 异常内部异常无法从传输连接读取数据 非阻塞
  • Socat未关闭tcp连接

    I use socat 1 7 3 1 r0并在alpine 3 3linux服务器 socat d d d PTY link dev ttyFOOBAR echo 0 raw unlink close 0 TCP LISTEN 7000
  • 我的代码中某处存在无限循环

    我有这个 Java 游戏服务器 最多可处理 3 000 个 tcp 连接 每个玩家或每个 tcp 连接都有自己的线程 每个线程的运行情况如下 public void run try String packet char charCur ne
  • TCP 兼容性:为什么 TCP 不兼容数据包广播和组播操作?

    http en wikipedia org wiki User Datagram Protocol http en wikipedia org wiki User Datagram Protocol 与 TCP 不同 UDP 与数据包广播
  • syn队列和accept队列的混淆

    在阅读TCP源码时 我发现一个困惑的事情 我知道 TCP 在 3 次握手中有两个队列 第一个队列存储服务器收到的连接SYN并发回ACK SYN 我们称之为同步队列 第二个队列存储3WHS成功并建立连接的连接 我们称之为接受队列 但在阅读代码
  • Web 服务器可以处理多少个套接字连接?

    假设我要获得共享 虚拟或专用托管 我在某处读到服务器 计算机一次只能处理 64 000 个 TCP 连接 这是真的吗 无论带宽如何 任何类型的托管可以处理多少个 我假设 HTTP 通过 TCP 工作 这是否意味着只有 64 000 个用户可
  • 如何在java应用程序中检测FIN - tcp标志?

    我在两台计算机之间有持久的 TCP 连接 第二台计算机不受我的控制 第二台计算机可以随时发送FIN标志 并且首先必须关闭当前连接 将FIN标志发送回第二台计算机 我如何知道第二台计算机正在发送 FIN 标志 以及何时必须调用 Java 应用
  • 两个http请求可以合并在一起吗?如果可以的话,nodeJS服务器如何处理呢?

    昨天我做了一些关于 NodeJS 的演讲 有人问我以下问题 我们知道nodeJS是一个单线程服务器 多个请求是 到达服务器并将所有请求推送到事件循环 如果什么 两个请求同时到达服务器 服务器将如何处理 处理这种情况 我猜到了一个想法并回复如
  • 如何在Linux中打开端口[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我已经安装了 Web 应用程序 该应用程序在 RHEL centOS 上的端口 8080 上运行 我只能通过命令行访问该机器 我尝试从我的
  • ZeroMQ可以用来接受传统的套接字请求吗?

    我正在尝试使用 ZeroMQ 重写我们的旧服务器之一 现在我有以下服务器设置 适用于 Zmq 请求 using var context ZmqContext Create using var server context CreateSoc
  • 视频流上的 TCP 与 UDP

    我刚从网络编程考试回来 他们问我们的问题之一是 如果您要传输视频 您会使用 TCP 还是 UDP 请解释一下存储视频和实时视频流 对于这个问题 他们只是希望得到一个简短的答案 TCP 用于存储视频 UDP 用于实时视频 但我在回家的路上想到
  • 我应该害怕使用 UDP 进行客户端/服务器广播通话吗?

    我在过去的两天里阅读了每一篇StackOverflow问题和答案 以及googling当然 关于印地TCP and UDP协议 以便决定在我的用户应用程序和 Windows 服务之间的通信方法中应该使用哪一种 从我目前所看到的来看 UDP是
  • 访问 AWS 上的 Tensorboard

    我正在尝试访问 AWS 上的 Tensorboard 这是我的设置 张量板 tensorboard host 0 0 0 0 logdir train 在端口 6006 上启动 TensorBoard b 39 您可以导航到http 172
  • iOS 上的多个 HTTP 请求与单个 TCP 连接

    我正在开发一个 iPhone 应用程序 它使用我控制的基于 Web 的 API 连接到持续打开的 TCP 端口并通过 TCP API 发出请求 或者为我想要获取的所有数据发出新的 HTTP 请求 会更快或更高效吗 我认为差异可以忽略不计 但
  • 中断 Select 以添加另一个要在 Python 中监视的套接字

    我正在 Windows XP 应用程序中使用 TCP 实现点对点 IPC 我正在使用select and socketPython 2 6 6 中的模块 我有三个 TCP 线程 一个读取线程通常会阻塞select 一个通常等待事件的写入线程

随机推荐

  • PG-REINFORCE tensorflow 2.0

    REINFORCE 算法实现 REINFORCE算法是策略梯度算法最原始的实现算法 xff0c 这里采用tensorflow2 0进行实现 span class token keyword import span tensorflow sp
  • DDPG tensorflow 2.0

    DDPG算法的tensorflow2 0实现 算法的详细解析可以看DDPG解析 span class token keyword import span tensorflow span class token keyword as span
  • MADDPG tensorflow2.0

    MADDPG 的 tensorflow2 0实现 环境 MPE 对MPE环境进行了一些简单的修改 xff0c 目前只在MPE中的simple spread上进行了简单的测试 MADDPG代码 代码由于是自己写的 xff0c 可能有一些错误
  • 最短探索时间的一种想法——MADDPG

    前言 最近在做maddpg相关的项目时候 xff0c 涉及到了一些在固定地图的场景下 xff0c 采取何种探索方式 xff0c 能够使在最短的时间内 xff0c 探索尽可能多的地图内容 xff0c 对此做了一些努力 xff0c 一些朋友对此
  • 在NVIDIA Jetson Xavier NX上使用tensorflow-gpu

    在NVIDIA Jetson Xavier NX上使用tensorflow gpu 目前所做的项目需要在NVIDIA Jetson Xavier NX的ubuntu18 04的系统下配置ROS xff0c python3以及tensorfl
  • CSDN最全数学公式

    CSDN中的数学公式 1 加减乘除 a 43 b a 43 b a 43 b xff1a a 43 b a
  • 数据结构体系复构

    1 数组 数组是可以再内存中连续存储多个元素的结构 xff0c 在内存中的分配也是连续的 xff0c 数组中的元素通过数组下标进行访问 xff0c 数组下标从0开始 数组运算 xff1a 遍历 xff1a 遍历所有元素并进行打印 插入 xf
  • 指向void的指针

    万能指针 一个指向任何对象类型的指针都可以赋值给类型为void 的变量 xff0c void 可以赋值给另外一个void xff0c 俩个void 可以比较相等与否 xff0c 而且可以显式地将void 转换到另一个类型 其他操作都是不安全
  • nano 命令

    Nano命令指南 打开文件与新建文件 使用nano打开或新建文件 xff0c 只需键入 xff1a 代码 1 1 打开或新建文件 nano 文件名 Nano是一种单模式编辑器 xff0c 你可以直接输入文字 如果你要编辑一个像 etc fs
  • 四轴飞控pid simulink仿真

    今天是我写的第一篇博客hhh xff0c 可能文章思路混乱 xff0c 大家海涵 最近想自己用stm32搞一个四轴飞行器的飞控 xff0c 现在进展比较缓慢 xff0c 主要受制于想做一个wifi无线透传的视频实时传递 用了一个新的模块 x
  • 蓝桥杯嵌入式客观题总结

    一 CPU芯片 xff1a STM32F103RBT6 STM32 xff1a 32位的MCU xff08 ST 意法半导体公司 M xff1a 微控制器 32 xff1a 32bit xff09 F 61 通用类型 103 xff1a 中
  • 大学Python编程试卷真题!用python循环,输出1+11+111+1111+11111的值

    你用过的Python的库有哪些 分别用于工作中什么场景 这个是上一期讲的面试题拓展 那今天来再拓展一下 xff0c 讲一个算法题 利用python循环 xff0c 输出1 43 11 43 111 43 1111 43 11111的值 这个
  • Dockerfile 部署springboot 项目暨保留字指令讲解

    Dockerfile 部署springboot 项目暨保留字指令讲解 一 系统环境二 springboot 项目部署2 1 springboot 项目准备2 2 上传jar2 3 编写dockerfile 文件2 4 构建镜像并运行 三 保
  • ubuntu系统使用LVM,实现减小root分区并扩充swap交换分区(至最大8G)

    xff08 在安装系统时安装LVM逻辑卷管理 1 减小root分区 无法在线缩减root分区系统文件大小 xff0c 必须进入救援模式 xff08 使用启动盘 xff09 在救援模式下 xff0c 打开终端 执行 sudo lvscan 或
  • SLAM机器人开发(五)使用Improved_ORBSLAM2实时稠密重建教程

    使用Improved ORBSLAM2实时稠密重建教程 搭建ROS环境安装依赖库运行ORBSLAM2 App转换为Octomap地图并实现导航 在 SLAM机器人开发专栏中 xff0c 上一篇介绍了ORBSLAM的原理和一系列开源库 xff
  • ROS系列书籍--机械工业出版社

    ROS系列书籍 机械工业出版社 1 ROS机器人开发实践 xff08 作者 xff1a 胡春旭 xff09 2 机器人ROS开发实践 xff08 作者 xff1a 无为斋主 xff09 3 ROS机器人编程实践 xff08 作者 xff1a
  • 问题解决-----解决ROS程序注册(source devel/setup.bash)只在当前终端生效的问题

    64 TOC 解决ROS程序注册 source devel setup bash 只在当前终端生效的问题目录 在进行ROS的嵌入式编程的时候 xff0c 每次程序编写完成 xff0c 都需要进行编译 xff0c 这是ROS嵌入式开发的必要步
  • ROS学习【10】-----搭建Gazebo机器人物理仿真环境并展示空环境中的机器人

    ROS学习 搭建Gazebo机器人物理仿真环境并展示空环境中的机器人模型目录 一 运行Gazebo 查看是否能够正常打开程序1 新建一个终端 xff0c 运行Gazebo仿真软件2 应对Gazebo程序闪退的方法 二 搭建Gazebo机器人
  • 问题解决-----ROS中Gazebo学习的问题解决合集(初次运行黑屏、运行launch文件后闪退、黑屏;gazebo联合rviz出现process has died等的解决办法)

    问题解决 ROS中gazebo环境搭建学习的问题解决合集目录 一 初次运行Gazebo出现黑屏1 问题描述 xff1a 2 问题原因3 解决方法 二 编译gazebo的功能包出现编译错误1 问题描述2 问题原因3 解决方法 三 运行laun
  • TCP传输大文件(图片、文档)

    遇到TCP传输大文件问题 xff0c 主要是 xff08 1 xff09 传输快 xff0c 但拼接成的大文件数据错 xff08 2 xff09 加校验 xff0c 传输变慢 xff08 3 xff09 接收包数跟发送包数不对应 费了一段时