http://www.cnblogs.com/wunaozai/p/3886588.html

这个系列是准备讲基于Linux Socket进行文件传输。简单的文件传输就是客户端可以上传文件,可以从服务器端下载文件。就这么两个功能如果再加上身份验证,就成了FTP服务器了,如果对用户的操作再加上一些功能(如分享),就可以作为一个最简单的网盘了。想想是不是有点小激动啊。

  我这一小节就不讲那么高级的东西,就先了解文件怎么传输,我们以前的聊天程序传输数据都是一次发送就完成本次的发送,因为一个sendBuf是足够的。但是对于二进制文件来说,文件的大小就不一定了,有可能很大,所以我们的Buf是不知道要多少的。所以要传输大文件,就要分多次传输,然后在目的地进行合并。这样就可以实现大文件传输了。传输的方法有两种,一种是串行一种是并行。我接下来要实现的代码是使用串行传输的,因为比较简单,而并行传输,比较复杂,要传输几个控制信号,保证数据合并重整后不会出错。并行可以使用多进(线)程。优点是可以同时传输多个文件,串行是只能一次传输一个文件。我们看一下网盘,大多是可以下载多个文件(多任务)是吧?应该用的就是并行了。如果只是从原理上讲串行的传输速度肯定是比并行的快,因为并行还要控制信号要传,而且还要重新合并整合成一个文件。既然这样那为什么所有的网盘都是使用多任务下载呢?(多个任务同时下载,每个任务同时还有多个端口在接收数据)。是因为我们所处的网络环境问题。我们的网络环境并不是那么的稳定,如果只是用一个端口进行串行传输,那么如果网络突然中断或者什么原因,导致服务器与客户端暂时连接断开。那么我们之前传的数据就要重传了。这就是为什么今天下载个任务到80%,然后明天还可以接着下载了。如果是一次性串行传输就不行了。你就会问,那在串行传输再加个控制信号不就行了?那这样的话,与并行区别就不大了。

  废话说了一大堆,到了真正要写代码的时候我还是使用串行来写,因为比较容易实现。(求原谅!)

  实现客户端向服务器发送一个指定的二进制文件

  client.cpp (为什么用cpp了,因为上次用c,然后代码越写越多,结果很多变量都写在开头,找起来不是很方便,所以用cpp了,哎,用c++就是为了用这个,会不会被骂?)

 1 #include <netinet/in.h> // sockaddr_in
 2 #include <sys/types.h> //socket
 3 #include <sys/socket.h> //socket
 4 #include <netdb.h> //gethostbyname
 5 #include <unistd.h> //close
 6 #include <stdio.h>
 7 #include <stdlib.h>
 8 #include <string.h>
 9 #include <time.h>
10 #include <arpa/inet.h> //inet_addr
11
12 #define SERVVER_PORT 12138
13 #define LISTEN_QUEUE 20
14 #define BUFFER_SIZE 1024
15
16 struct Addr
17 {
18     char host[64];
19     int port;
20 };
21
22 int file_push(struct Addr addr,char *filenames)
23 {
24     struct sockaddr_in servAddr;
25     struct hostent * host;
26     int sockfd;
27     FILE *fp;
28
29     host=gethostbyname(addr.host);
30     servAddr.sin_family=AF_INET;
31     servAddr.sin_addr=*((struct in_addr *)host->h_addr);
32     //servAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
33     servAddr.sin_port=htons(addr.port);
34     if(host==NULL)
35     {
36         perror("获取IP地址失败");
37         exit(-1);
38     }
39     if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
40     {
41         perror("socket创建失败");
42         exit(-1);
43     }
44
45     if(connect(sockfd,(struct sockaddr *)&servAddr,sizeof(struct sockaddr_in))== -1)
46     {
47         perror("connect 失败");
48         exit(-1);
49     }
50
51     //打开文件
52     if((fp=fopen(filenames,"rb"))==NULL)
53     {
54         perror("文件打开失败");
55         exit(-1);
56     }
57     char buffer[BUFFER_SIZE];
58     bzero(buffer,BUFFER_SIZE);
59     printf("正在传输文件");
60     int len=0;
61     //不断的读取文件直到文件结束
62     while((len=fread(buffer,1,BUFFER_SIZE,fp))>0)
63     {
64         if(send(sockfd,buffer,len,0)<0)
65         {
66             perror("发送数据失败");
67             exit(-1);
68         }
69         bzero(buffer,BUFFER_SIZE);
70         printf(".");//1K打印一个点//如果要实现百分比,就要计算文件大小,然后再处理即可
71     }
72
73     fclose(fp);//关闭文件流
74     close(sockfd);//关闭socket连接
75
76     return 0;
77 }
78
79 int main(int argc,char *argv[])
80 {
81     char orderbuf[BUFFER_SIZE];
82     char orderch[BUFFER_SIZE];
83     struct Addr addr;
84
85     strcpy(addr.host,argv[1]);
86     addr.port=atoi(argv[2]);
87     while(1)
88     {
89         printf("\n请输入文件名:");
90         fgets(orderbuf,BUFFER_SIZE,stdin);
91         orderbuf[strlen(orderbuf)-1]=0;//去掉获取到的回车符
92         //printf("%s\n",orderbuf);
93         file_push(addr,orderbuf);
94     }
95
96     return 0;
97 }

  server.cpp

  1 #include <netinet/in.h>
  2 #include <sys/types.h>
  3 #include <sys/socket.h>
  4 #include <stdlib.h>
  5 #include <time.h>
  6 #include <string.h>
  7 #include <unistd.h>
  8 #include <stdio.h>
  9 #include <arpa/inet.h> //inet_ntoa
 10
 11 #define SERVER_PORT 12138
 12 #define LISTEN_QUEUE 20
 13 #define BUFFER_SIZE 1024
 14
 15 void print_time(char *ch);//打印时间
 16
 17 int main(int argc,char *argv[])
 18 {
 19     struct sockaddr_in server_addr;
 20     bzero(&server_addr,sizeof(server_addr));
 21     server_addr.sin_family=AF_INET;
 22     server_addr.sin_addr.s_addr=htons(INADDR_ANY);
 23     server_addr.sin_port=htons(SERVER_PORT);
 24
 25     //创建套接字
 26     int sockfd=socket(AF_INET,SOCK_STREAM,0);
 27     if(sockfd<0)
 28     {
 29         perror("创建套接字失败");
 30         exit(-1);
 31     }
 32
 33     if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr))==-1)
 34     {
 35         perror("bind 失败");
 36         exit(-1);
 37     }
 38
 39     if(listen(sockfd,LISTEN_QUEUE))
 40     {
 41         perror("listen 失败");
 42         exit(-1);
 43     }
 44
 45     while(1)
 46     {
 47         pid_t pid;
 48         struct sockaddr_in client_addr;
 49         socklen_t length=sizeof(client_addr);
 50         int clientfd=accept(sockfd,(struct sockaddr *)&client_addr,&length);
 51         if(clientfd==-1)
 52         {
 53             perror("accept 失败");
 54             continue;
 55         }
 56         else
 57         {
 58             printf("客户端%s:%d连接成功\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
 59             pid=fork();
 60             if(pid<0)
 61             {
 62                 perror("创建进程失败");
 63             }
 64             else if(pid==0)/*child*/
 65             {
 66                 char buffer[BUFFER_SIZE];
 67                 int data_len;
 68                 FILE * fp=NULL;
 69                 bzero(buffer,BUFFER_SIZE);
 70                 if((fp=fopen("data","wb"))==NULL)
 71                 {
 72                     perror("文件打开失败");
 73                     exit(-1);
 74                 }
 75                 //循环接收数据
 76                 int size=0;//表示有多少个块
 77                 while(data_len=recv(clientfd,buffer,BUFFER_SIZE,0))//data_len为0时结束,是因为当客户端没有再发送数据过来时是接收0的,也表示该文件传输完毕了。
 78                 {
 79                     if(data_len<0)
 80                     {
 81                         perror("接收数据错误");
 82                         exit(-1);
 83                     }
 84                     size++;
 85                     if(size==1)
 86                     {
 87                         printf("正在接收来自%s:%d的文件\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
 88                     }
 89                     else
 90                     {
 91                         printf(".");
 92                     }
 93                     //向文件中写入
 94                     int write_len=fwrite(buffer,sizeof(char),data_len,fp);//向文件中写入,默认文件打开时会有一个文件指针进行写入。如果是并行传输就要修改这个文件指针了,还是有点麻烦的,如果是串行的,我们都不用管了,多方便。
 95                     if(write_len>data_len)
 96                     {
 97                         perror("写入数据错误");
 98                         exit(-1);
 99                     }
100                     bzero(buffer,BUFFER_SIZE);
101                 }
102                 if(size>0)
103                 {
104                     printf("\n%s:%d的文件传送完毕\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
105                 }
106                 else
107                 {
108                     printf("\n%s:%d的文件传送失败\n",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));//如果传过来的文件大小为0,也是会出现这个错误
109                 }
110                 fclose(fp);
111                 //rename("data","asdf");//这里可以修改文件的名字。保存到服务器的话可以随便改个名字,防止文件名重复
112                 exit(0);
113             }
114             else /*pather*/
115             {
116                 ;
117             }
118         }
119         close(clientfd);
120     }
121
122     return 0;
123 }
124
125 void print_time(char *ch)
126 {
127     time_t now;
128     struct tm * stm;
129     time(&now);
130     stm=localtime(&now);
131     sprintf(ch,"%02d:%02d:%02d\n",stm->tm_hour,stm->tm_min,stm->tm_sec);
132     return ;
133 }

  两部分的代码都不难理解,关键的代码就是那个while循环了。这个就不给截图了,运行是没有问题。

  这篇杜鑫先生的回答很不错,可以看一下: http://www.zhihu.com/question/21591490

  本文地址: http://www.cnblogs.com/wunaozai/p/3886588.html

Socket网络编程--小小网盘程序(1)相关推荐

  1. Socket网络编程--小小网盘程序(5)

    http://www.cnblogs.com/wunaozai/p/3893469.html 各位好呀!这一小节应该就是这个小小网盘程序的最后一小节了,这一节将实现最后的三个功能,即列出用户在服务器中 ...

  2. Socket网络编程--小小网盘程序(4)

    在这一小节中实现了文件的下载,具体的思路是根据用户的uid和用户提供的文件名filename联合两张表,取得md5唯一标识符,然后操作这个标识符对应的文件发送给客户端. 实现下载的小小网盘程序 cli ...

  3. Socket网络编程--小小网盘程序(3)

    http://www.cnblogs.com/wunaozai/p/3891062.html 接上一小节,这次增加另外的两张表,用于记录用户是保存那些文件.增加传上来的文件的文件指纹,使用MD5表示. ...

  4. Socket网络编程--小小网盘程序(2)

    http://www.cnblogs.com/wunaozai/p/3887728.html 这一节将不会介绍太多的技术的问题,这节主要是搭建一个小小的框架,为了方便接下来的继续编写扩展程序.本次会在 ...

  5. Linux C 网络编程 仿照网盘的功能

    Linux C 网络编程 仿照网盘的功能 代码: gitbub 代码,欢迎下载测试 使用概述 启动 server-> make;./server ../conf/serverconf.ini c ...

  6. 5.3linux下C语言socket网络编程简例

    原创文章,转载请注明转载字样和出处,谢谢! 这里给出在Linux下的简单socket网络编程的实例,使用tcp协议进行通信,服务端进行监听,在收到客户端的连接后,发送数据给客户端:客户端在接受到数据后 ...

  7. linux下C语言socket网络编程简例

    转自博文:http://blog.csdn.net/kikilizhm/article/details/7858405 在练习写网络编程时,该例给了我帮助,在写服务器时,我把while逻辑位置想法错了 ...

  8. Linux C++/Java/Web/OC Socket网络编程

    一,Linux C++ Socket网络编程 1.什么是TCP/IP.UDP? TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制 ...

  9. Python Socket网络编程(二)局域网内和局域网与广域网的持续通信

    目录 前言 IP地址 简介 公有IP 私有IP 局域网之间网络通信 前提 功能描述 源码 运行结果 局域网与广域网网络通信 前提 源码 结语 前言 本系列博客是笔者学习Python Socket的过程 ...

最新文章

  1. fn hotkeys and osd_潍坊实习生活(3)and 绊 最后的进化
  2. pgsql thinkphp5_thinkphp 连接postgresql
  3. Python3网络爬虫开发实战,Cookies 池的搭建,破解反爬虫!
  4. 用css3制作一个Music Player Menu
  5. 刷前端面经笔记(九)
  6. 【Python】AttributeError: 'Series' object has no attribute 'order'
  7. android 崩溃捕获_Android从相机和图库捕获图像
  8. 前端----JavaScript
  9. javq接口_java中什么是接口?接口的作用是什么?
  10. 单片机简易开发板怎么设计,我来告诉你
  11. CNTV获首张互联网电视牌照
  12. win10自带虚拟机好用吗_虚拟机的新选择,win10自带Hyper-V 虚拟机
  13. 三角形周长最短问题_最短路径问题之三角形的周长最小
  14. 智能柜怎么与Android通信,快递智能柜Android系统该何去何从
  15. 大数据开发有哪些难点?
  16. HTML制作手风琴效果,Dreamweaver制作手风琴图片展示效果(附代码)
  17. 香港城市大学全奖PhD/联培PhD/博后/RA
  18. 深度学习项目实践——制作一个能一键更换证件照背景的软件
  19. Python数据分析 | Numpy基本属性介绍
  20. 写诗软件这里为什么会如此成功?

热门文章

  1. Delta DVP 系列 PLC 各装置 Modbus 地址
  2. 使用selenium进行密码破解(绕过账号密码JS加密)
  3. 第一次连接mysql失败_MySQL 远程连接失败
  4. php 打乱数组顺序_PHP实现大转盘抽奖算法
  5. react 判断图片是否加载完成_React中型项目的优化实践
  6. 华为root工具_华为Mate9解锁后无法ROOT 需要手动刷入Recovery怎么办【解决方法】...
  7. git push 的符号笔有什么用_如何同步多个 git 远程仓库
  8. python中print的用法_Python中print函数简单使用总结
  9. cannot convert ‘_IO_FILE*’ to ‘const char*
  10. python Requests登录GitHub