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

来源:互联网 发布:域名做企业邮箱 编辑:程序博客网 时间:2024/06/06 10:46
        我们天天用QQ传送文件,也习惯了用飞鸽传送文件。但里边的具体实现是怎么样的呢?其实,过程很多简单,相信大家都知道,我这里呢,就多此一举给大家详细分析分析,做个总结,也为网络程序的编写搭一个整体的框架。好了,现在开始,我会分为两个端来说明:客户端和服务器端。今天先说客户端,下次再说服务器端。
        直接上源码,来的简单实用且讲解不费劲,文中的代码是完整的代码,行文中蓝色部分是说明部分,使用时去掉及可以了,现在开始:

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

int main(int argc,char**argv){    if(argc !=2) //输入命令提示信息    {        printf("Please enter command like this: %s ServerIPAddress\n",argv[0]);        exit(1);    }    int i=0;    for(i;i<1000;i++)    //做循环是为了不想结束程序,想多次传输        SendRequest(argv);     //传输的核心当然是从这里开始了    return 0;}
        通过上面我们知道了问题的核心就集中在SendRequest(argv)上,我们继续往下走:

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

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

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

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

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

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

    close(fp);    close(client_socket);}

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


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

原创粉丝点击