基于linux的文件传输器实现详解----客户端实现详解

  我们天天用QQ传送文件,也习惯了用飞鸽传送文件。但里边的具体实现是怎么样的呢?其实,过程很多简单,相信大家都知道,我这里呢,就多此一举给大家详细分析分析,做个总结,也为网络程序的编写搭一个整体的框架。好了,现在开始,我会分为两个端来说明:客户端和服务器端。今天先说客户端,下次再说服务器端。

       直接上源码,来的简单实用且讲解不费劲,文中的代码是完整的代码,行文中蓝色部分是说明部分,使用时去掉及可以了,现在开始:

       作为C语言,当然是先来个main()了:

view source print ?
01 int main(int argc,char**argv)
02 {
03     if(argc !=2) //输入命令提示信息
04     {
05         printf("Please enter command like this: %s ServerIPAddress\n",argv[0]);
06         exit(1);
07     }
08     int i=0;
09     for(i;i<1000;i++)    //做循环是为了不想结束程序,想多次传输
10         SendRequest(argv);     //传输的核心当然是从这里开始了
11     return 0;
12 }

       通过上面我们知道了问题的核心就集中在SendRequest(argv)上,我们继续往下走:

view source print ?
01 void SendRequest(char**argv)
02 {   
03     int client_socket = socket(AF_INET,SOCK_STREAM,0);   //创建客户端连接套接字
04     int ret;  //建立连接的返回值
05     if(client_socket<0)
06     {
07         printf("Create socket failed!\n");
08         exit(1);
09     }   
10     struct sockaddr_in server_addr;  //设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
11     bzero(&server_addr,sizeof(server_addr));
12     server_addr.sin_family = AF_INET;   
13     if(inet_aton(argv[1],&server_addr.sin_addr)==0) //服务器的IP地址来自程序的参数 
14     {//inet_aton将一个参数的点分十进制IP地址转换为32位网络字节序二进制IP地址
15         printf("Server IP address error!\n");
16         exit(1);
17     }
18     server_addr.sin_port = htons(SERVER_PORT);
19     socklen_t server_addr_length = sizeof(server_addr); 
20     //向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
21     if((ret=connect(client_socket,(struct sockaddr*)&server_addr,server_addr_length))<0)
22     {
23             printf("Connect %s failed!\n",argv[1]);
24         exit(1);
25     }

       上边这段应该还行吧,先创建一个客户端套接口,这个很重要,后面的和服务器连接,接收服务器信息都用这个套接口。然后就是定义服务器端套接口(server_addr),里边包含了IP地址啦,端口信息啦,反正靠这个就能找到远端服务器,接下来,就是将我们刚创建的本地套接口client_socket和服务器套接口建立一个通信管道(连接),这里很明显就是connect,是不。继续:

view source print ?
1 char file_name[FILE_NAME_MAX_SIZE+1];  //存储文件名的缓冲区
2 bzero(file_name,FILE_NAME_MAX_SIZE+1);
3 printf("Please enter the file name you want to open:\t");
4 scanf("%s",file_name);     //输入要获得的文件的名(对应服务器端的完整路径)
5 char buffer[BUFFER_SIZE];
6 bzero(buffer,BUFFER_SIZE);
7 strncpy(buffer,file_name,strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));
8 send(client_socket,buffer,BUFFER_SIZE,0);   //向服务器发送buffer中的数据,就是告诉服务器我要buffer里对应的文件
9 FILE * fp = fopen(file_name,"w");           //同时在本地建立一个这样的文件,以便后面服务器传来的文件内容放进去

       这一段也应该没有问题,注释中已经说的很明白了。一旦在上面建立了连接,这时就要告诉服务器我要接受你的啥文件(file_name),然后本地创建一个文件以便准备接收服务器传过来的东西。

view source print ?
01 bzero(buffer,BUFFER_SIZE);   //刚buffer里存的是客户端想要的文件名,现在我们里边打算放服务器传过来的文件内容
02 int length = 0;
03 int write_length=0;      //每次从服务器端接收文件内容的大小
04 while(length=recv(client_socket,buffer,BUFFER_SIZE,0))    //文件可能很大,一次只能接收一点,所以当然要用循环接收完
05 {//client_socket派上用场了,我前边说过,它和服务器的套接口地址信息建立了一个管道,那么服务器来的信息当然就存在它里边了,我们只要拷贝到buffer就好了
06     if(length<0)    //奇怪,我居然没从里边接收到内容即内容长度为空
07     {
08         printf("Receive data from %s failed!\n",argv[1]);
09         break;
10     }
11     write_length = fwrite(buffer,sizeof(char),length,fp);  //成功的服务器写入客户端套接字的client_socket中读到了数据,那就写到fp中吧
12     if(write_length<length)   //写入的怎么会小于接收到的呢, 肯定出错了
13     {
14         printf("File %s write failed!\n",file_name);
15         break;
16     }
17     bzero(buffer,BUFFER_SIZE);    //为了避免混淆,还是清空接收的缓冲区吧
18 }
19  
20 if(write_length<=0)    //这明显是出错了啊
21 {
22     printf("File %s dosen't exist!\n",file_name);
23     exit(1);
24 }

       这一段是关键,我刚才说了,既然在本地套接口client_socket和服务器信息套接口地址上建立了连接,那么和服务器的所有通信就丢给了client_socket.一旦服务器有信息要写回给客户端,客户端的接口就是client_socket,r,然后我们只要把这里边的信息写入buffer,然后把buffer里的信息写入本地文件的文件描述符就好了(fd).最后说明的是我们用了循环,是因为谁也不能拍着胸脯说,能一下子接收完,网络的能力还是有限的,那就循环判断当服务器发过来的信息长度为0时,我就认为是传输结束了。当所有的一切都结束了,好那就关闭以前建立的连接啦,文件描述符啦,套接口啦:

view source print ?
1     close(fp);
2     close(client_socket);
3 }

       代码讲完了,其实相当简单,刚都说了,我是多此一举来总结下大家都知道,最后给你一个流程图:

                 基于linux的文件传输器实现详解----客户端实现详解_第1张图片

       有了上面的流程图,现在清晰多了,服务器端的部分,我下次再讲。 

你可能感兴趣的:(基于linux的文件传输器实现详解----客户端实现详解)