C++大文件传输

C/C++大文件/数据网络传输方法总结

在C/C++网络编程中不免会遇到需要传输大数据、大文件的情况,而由于socket本身缓冲区的限制,大概一次只能发送4K左右的数据,所以在传输大数据时客户端就需要进行分包,在目的地重新组包。而实际上已有一些消息/通讯中间件对此进行了封装,提供了直接发送大数据/文件的接口;除此之外,利用共享目录,ftp,ssh等系统命令来实现大文件/数据也不失为一种好的方法。

1.基础的基于socket进行传输

基础的基于socket进行传输关键在于控制,需要自己行分包和组包。

原理很简单那,我们就直接看一下代码吧。

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

    //////////////////////////////////////////////////////////////////////// 

    //
file_server.c -- socket文件传输服务器端示例代码  

    //
///////////////////////////////////////////////////////////////////// 

    #include<netinet
in.h=
"">  

    #include<sys
types.h=
"">  

    #include<sys
socket.h=
"">  

    #include<stdio.h>  

    #include<stdlib.h>  

    #include<string.h>  

      

    #define
HELLO_WORLD_SERVER_PORT   
6666

    #define
LENGTH_OF_LISTEN_QUEUE    
20

    #define
BUFFER_SIZE               
1024

    #define
FILE_NAME_MAX_SIZE        
512

      

    int

main(
int

argc,
char

**argv) 

    

        //
set socket‘s address information  

        //
设置一个socket地址结构server_addr,代表服务器internet的地址和端口 

        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(HELLO_WORLD_SERVER_PORT); 

      

        //
create a stream socket  

        //
创建用于internet的流协议(TCP)socket,用server_socket代表服务器向客户端提供服务的接口 

        int

server_socket = socket(PF_INET, SOCK_STREAM,
0); 

        if

(server_socket <
0

        

            printf(Create
Socket Failed!

); 

            exit(1); 

        

      

        //
把socket和socket地址结构绑定  

        if

(bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr))) 

        

            printf(Server
Bind Port: %d Failed!

,
HELLO_WORLD_SERVER_PORT); 

            exit(1); 

        

      

        //
server_socket用于监听  

        if

(listen(server_socket, LENGTH_OF_LISTEN_QUEUE)) 

        

            printf(Server
Listen Failed!

); 

            exit(1); 

        

      

        //
服务器端一直运行用以持续为客户端提供服务  

        while(1

        

            //
定义客户端的socket地址结构client_addr,当收到来自客户端的请求后,调用accept 

            //
接受此请求,同时将client端的地址和端口等信息写入client_addr中 

            struct
sockaddr_in client_addr; 

            socklen_t         
length = sizeof(client_addr); 

      

            //
接受一个从client端到达server端的连接请求,将客户端的信息保存在client_addr中 

            //
如果没有连接请求,则一直等待直到有连接请求为止,这是accept函数的特性,可以 

            //
用select()来实现超时检测  

            //
accpet返回一个新的socket,这个socket用来与此次连接到server的client进行通信 

            //
这里的new_server_socket代表了这个通信通道 

            int

new_server_socket = accept(server_socket, (struct sockaddr*)&client_addr, &length); 

            if

(new_server_socket <
0

            

                printf(Server
Accept Failed!

); 

                break

            

      

            char

buffer[BUFFER_SIZE]; 

            bzero(buffer,
sizeof(buffer)); 

            length
= recv(new_server_socket, buffer, BUFFER_SIZE,
0); 

            if

(length <
0

            

                printf(Server
Recieve Data Failed!

); 

                break

            

      

            char

file_name[FILE_NAME_MAX_SIZE +
1]; 

            bzero(file_name,
sizeof(file_name)); 

            strncpy(file_name,
buffer, 

                    strlen(buffer)
> FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer)); 

      

            FILE
*fp = fopen(file_name, r); 

            if

(fp == NULL) 

            

                printf(File:   
%s Not Found!

,
file_name); 

            

            else

            

                bzero(buffer,
BUFFER_SIZE); 

                int

file_block_length =
0

                while(
(file_block_length = fread(buffer, sizeof(
char),
BUFFER_SIZE, fp)) >
0

                

                    printf(file_block_length
= %d

,
file_block_length); 

      

                    //
发送buffer中的字符串到new_server_socket,实际上就是发送给客户端 

                    if

(send(new_server_socket, buffer, file_block_length,
0)
<
0

                    

                        printf(Send
File:   %s Failed!

,
file_name); 

                        break

                    

      

                    bzero(buffer,
sizeof(buffer)); 

                

                fclose(fp); 

                printf(File:   
%s Transfer Finished!

,
file_name); 

            

      

            close(new_server_socket); 

        

      

        close(server_socket); 

      

        return

0

    
</string.h></stdlib.h></stdio.h></sys></sys></netinet>

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

    ////////////////////////////////////////////////////// 

    //
file_client.c  socket传输文件的client端示例程序  

    //
/////////////////////////////////////////////////// 

    #include<netinet
in.h=
"">                        
//
for sockaddr_in 

    #include<sys
types.h=
"">                         
//
for socket 

    #include<sys
socket.h=
"">                        
//
for socket 

    #include<stdio.h>                             
//
for printf 

    #include<stdlib.h>                            
//
for exit 

    #include<string.h>                            
//
for bzero 

      

    #define
HELLO_WORLD_SERVER_PORT      
6666

    #define
BUFFER_SIZE                  
1024

    #define
FILE_NAME_MAX_SIZE           
512

      

    int

main(
int

argc,
char

**argv) 

    

        if

(argc !=
2

        

            printf(Usage:
./%s ServerIPAddress

,
argv[
0]); 

            exit(1); 

        

      

        //
设置一个socket地址结构client_addr, 代表客户机的internet地址和端口 

        struct
sockaddr_in client_addr; 

        bzero(&client_addr,
sizeof(client_addr)); 

        client_addr.sin_family
= AF_INET;
//
internet协议族 

        client_addr.sin_addr.s_addr
= htons(INADDR_ANY);
//
INADDR_ANY表示自动获取本机地址 

        client_addr.sin_port
= htons(
0);
//
auto allocated, 让系统自动分配一个空闲端口 

      

        //
创建用于internet的流协议(TCP)类型socket,用client_socket代表客户端socket 

        int

client_socket = socket(AF_INET, SOCK_STREAM,
0); 

        if

(client_socket <
0

        

            printf(Create
Socket Failed!

); 

            exit(1); 

        

      

        //
把客户端的socket和客户端的socket地址结构绑定  

        if

(bind(client_socket, (struct sockaddr*)&client_addr, sizeof(client_addr))) 

        

            printf(Client
Bind Port Failed!

); 

            exit(1); 

        

      

        //
设置一个socket地址结构server_addr,代表服务器的internet地址和端口 

        struct
sockaddr_in  server_addr; 

        bzero(&server_addr,
sizeof(server_addr)); 

        server_addr.sin_family
= AF_INET; 

      

        //
服务器的IP地址来自程序的参数  

        if

(inet_aton(argv[
1],
&server_addr.sin_addr) ==
0

        

            printf(Server
IP Address Error!

); 

            exit(1); 

        

      

        server_addr.sin_port
= htons(HELLO_WORLD_SERVER_PORT); 

        socklen_t
server_addr_length = sizeof(server_addr); 

      

        //
向服务器发起连接请求,连接成功后client_socket代表客户端和服务器端的一个socket连接 

        if

(connect(client_socket, (struct sockaddr*)&server_addr, server_addr_length) <

0

        

            printf(Can
Not Connect To %s!

,
argv[
1]); 

            exit(1); 

        

      

        char

file_name[FILE_NAME_MAX_SIZE +
1]; 

        bzero(file_name,
sizeof(file_name)); 

        printf(Please
Input File Name On Server.    ); 

        scanf(%s,
file_name); 

      

        char

buffer[BUFFER_SIZE]; 

        bzero(buffer,
sizeof(buffer)); 

        strncpy(buffer,
file_name, strlen(file_name) > BUFFER_SIZE ? BUFFER_SIZE : strlen(file_name)); 

        //
向服务器发送buffer中的数据,此时buffer中存放的是客户端需要接收的文件的名字 

        send(client_socket,
buffer, BUFFER_SIZE,
0); 

      

        FILE
*fp = fopen(file_name, w); 

        if

(fp == NULL) 

        

            printf(File:   
%s Can Not Open To Write!

,
file_name); 

            exit(1); 

        

      

        //
从服务器端接收数据到buffer中  

        bzero(buffer,
sizeof(buffer)); 

        int

length =
0

        while(length
= recv(client_socket, buffer, BUFFER_SIZE,
0)) 

        

            if

(length <
0

            

                printf(Recieve
Data From Server %s Failed!

,
argv[
1]); 

                break

            

      

            int

write_length = fwrite(buffer, sizeof(
char),
length, fp); 

            if

(write_length < length) 

            

                printf(File:   
%s Write Failed!

,
file_name); 

                break

            

            bzero(buffer,
BUFFER_SIZE); 

        

      

        printf(Recieve
File:     %s From Server[%s] Finished!

,
file_name, argv[
1]); 

      

        //
传输完毕,关闭socket  

        fclose(fp); 

        close(client_socket); 

        return

0

      

    

</string.h></stdlib.h></stdio.h></sys></sys></netinet>

2.使用现有的通讯中间件

2.1 ActiveMQ 传送文件接口

为了解决传输大文件的问题,ActiveMQ在jms规范之外引入了jms streams的概念。PTP模式下,连到同一个destination的两端,可以通过broker中转来传输大文件。

发送端使用connection.createOutputStream打开一个输出流,往流里写文件。

OutputStream out =connection.createOutputStream(destination);

接收端则简单的使用connection.createInputStream拿到一个输入流,从中读取文件数据即可。

?


1

InputStream
in = connection.createInputStream(destination)

详见:http://activemq.apache.org/jms-streams.html

2.2 ZeroMQ 接口

ZeroMQ没有直接提供传送文件的接口。但ZeroMQ中send(void * data, size_t len)接口已经做好了封装,可以send任意大小的数据。代码如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

zmq::context_t
ctx(
1);

zmq::socket_t
sock(ctx, ZMQ_REQ);

sock.connect(tcp://192.168.20.111:20310);

sock.send(pData,len);//数据大小没有限制,可以直接发送任意大小的数据

char

reply[
100];

sock.recv
(reply,
100);

sock.disconnect(addr);

接收端代码如下:

?


1

2

3

4

5

6

7

8

9

10

m_context
=
new

zmq::context_t(
1);

    m_socket
=
new

zmq::socket_t (*m_context, ZMQ_REP);

    m_socket->bind
(tcp:
//*:20310);

    zmq::message_t
request;

        //
Wait for next request from client

        m_socket->recv
(&request)
//
request可以接受发送来的任意大小的数据

        

        m_socket->send(ok,2);

是不是很简单呢?

3.基于共享文件、ftp、scp等

这就不细说了。要么就是写共享目录,要么就是调用系统命令。

4.总结

1)直接基于socket编程难度较高,所以不推荐。

2)使用现有的库方便,但需要学习。一般推荐。

3)共享文件、ftp、scp等难度低,简单易用,在符合使用场景时是首选。(但一些自命不凡的程序员或许会对你嗤之以鼻,考虑之...)

C++大文件传输

时间: 2024-08-03 15:50:38

C++大文件传输的相关文章

Windows下基于TCP协议的大文件传输(流形式)

简单实现TCP下的大文件高效传输 在TCP下进行大文件传输,不像小文件那样直接打包个BUFFER发送出去,因为文件比较大可能是1G,2G或更大,第一效率问题,第二TCP粘包问题.针对服务端的设计来说就更需要严紧些.下面介绍简单地实现大文件在TCP的传输应用. 粘包出现原因:在流传输中出现,UDP不会出现粘包,因为它有消息边界(参考Windows 网络编程) 1 发送端需要等缓冲区满才发送出去,造成粘包 2 接收方不及时接收缓冲区的包,造成多个包接收 解决办法: 为了避免粘包现象,可采取以下几种措

WCF大文件传输服务

由于项目需要,自己写一个基于WCF的大文件传输服务雏形.觉得有一定的参考价值,因此放在网上分享. 目前版本为v1.1特点如下: 1.文件传输端口为18650 2.上传和下载文件 3.支持获取文件传输状态(未开始.传输中.传输完成.出现错误) 4.支持获取文件传输进度(范围0~1) 5.支持获取文件传输速度速度(按文件传输速度大小 自动切换 KB/s 和 MB/s显示) 项目解决方案如下: 服务断包括WCF寄宿的控制台服务和Windows 服务以及文件传输服务核心 公共包括一些帮助类(文件HASH

WinSock实现的大文件传输

class file_send { public: SOCKET send_s; //The socket that used for sending which is established previously char * filename; //The full path of the file that the client requested void send_file() { percentage=0; FILE * pFile=fopen(filename,"rb")

networkcomms通信框架实现大文件传输

networkcomms2.3.1通信框架实现大文件传输(为节省空间,不包含通信框架源码,通信框架源码请另行下载) 文件传送在TCP通信中是经常用到的,本文针对文件传送进行探讨 经过测试,可以发送比较大的文件,比如1个G或者2个G 本文只对文件传送做了简单的探讨,示例程序可能也不是很成熟,希望本文起到抛砖引玉的作用,有兴趣的朋友帮忙补充完善 首先看一下实现的效果 服务器端: 客户端(一次只能发送一个文件): 服务器端收到的文件,存放到了D盘根目录下(存放的路径可以根据情况修改) 本程序基于开源的

支持断点续传的大文件传输协议

文件传输协议(FTP)是一个被广泛应用的网络协议,FTP技术作为文件传输的重要手段,在数据通信领域一直发挥着举足轻重的作用,不支持断点续传,是Internet上最早也是最广泛使用的应用之一. 从1971年A.K.Bhushan提出第一个FTP协议版本(RFC114)到现在,人们对FTP的应用已经历了40余年的时间,同时,许多基于FTP协议的数据传输软件也应运而生.如Windows操作系统下经常使用的支持FTP协议的软件有:CuteFTP.FlashFXP.迅雷(Thunder).快车(Flash

一个好用的大文件传输工具:支持选点续传、错误重传

数据正在爆炸式增长,几乎每两年翻一番.这些数据和文件可能是组织机构重要的业务数据,也可能是其重要的信息资源. 通常情况下,组织机构使用邮件.QQ.FTP等常规方式传输文件,但是当文件容量在2-3G以上时,上述方法就变得非常缓慢.如果文件更大时,快递硬盘等方式经常被使用,但是快递硬盘通常要花二三天的时间,不能满足及时获取文件的要求. 选择一个便捷的方法,高效传输和管理大文件,对于组织机构业务开展的来说非常重要.一个好的大文件传输解决方案至少应该包括以下特点: 优异的传输性能对于大文件传输来说,优异

如何分发大文件、大文件传输解决方案

随着云计算.大数据技术不断发展,4K 视频.虚拟现实(VR).视频直播等互联网应用领域不断升级更新,企业网.数据中心规模持续扩大,企业拥有的数据急剧增长,海量文件随之产生. 同时,互联网时代,众多行业都面临大型文件传输的问题,速度慢,是否安全,是优先考虑的前提! 一直以来,企业通常使用QQ软件.FTP.网盘或拆分数据.快递硬盘等方式进行海量文件上传和下载. 但是这些方式存在很多弊端,导致企业不能有效利用海量文件: 通常的一些方法: 1.使用QQ等软件直接对传:这种方法在线随时都可以传,比较方便,

服务器间大文件传输

前言在管理mysql,初始化服务器.复制和备份/还原,跨网络的传输大文件是很常见的操作.1.基本的操作 ● 压缩大文件 ● 发送到另一台服务器上 ● 解压大文件 ● 校验文件的完整性,是否有损坏2.具体的操作     (1)一般的步骤(scp)server1:gzip   -c   /backup/mysql/mytable.MYD     > mytable.MYD.gzscp    mytable.MYD.gz    [email protected]: /var/lib/mysql/ser

大文件传输工具

http://heylinux.com/archives/2984.html http://imysql.cn/2008_12_08_using_bbcp_instead_scp http://linux.cn/article-4527-1-rss.html http://teachmyself.blog.163.com/blog/static/188814229201242314917237/   由来: 局域网双机拷贝单个大文件 [200G大小],不要问我是啥! 也不要问我为毛会生成那么大的