Chinaunix首页 | 论坛 | 博客
  • 博客访问: 157556
  • 博文数量: 85
  • 博客积分: 366
  • 博客等级: 一等列兵
  • 技术积分: 455
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-16 18:32
个人简介

闲下来的时候看看书

文章分类

全部博文(85)

文章存档

2016年(1)

2013年(2)

2012年(81)

2011年(1)

我的朋友

分类:

2012-09-20 17:04:12

Andrew Huang 转载请注明作者及联络方式

一.文件下载原理
--------------------------------------------------------------

二.实现的代码
--------------------------------------------------------------

文件下载头文件

文件服务器代码 tcp_file_svr.c

/*
  TCP File Server
 
  Author :Andrew Huang

 */


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/stat.h>


#include <pthread.h>



#include <stdio.h>
#include <string.h>

#include "tcp_file.h"

#define DOWNLOAD_FILE "data.pdf"


int file_size(char * filename)
{
    struct stat st;
    if(stat(filename,&st)<0)
             return -1;
     return st.st_size;
}

static void * thread_fn(void *arg)
{
   int client_fd = (int)arg;
   int len,count = 0;
    char buf[1024];
    FILE_HDR header;


    
     strncpy(header.file_name,DOWNLOAD_FILE,sizeof(header.file_name));

    FILE * file = NULL;
     
     file = fopen(DOWNLOAD_FILE,"rb");
     if(file == NULL)
      {
         header.file_len = htonl(-100) ;
          send(client_fd,(void *)&header,sizeof(header),0);
        close(client_fd);
         return NULL;
      }

        len = file_size(DOWNLOAD_FILE);

      printf("send file %s ,len %d to client\n",DOWNLOAD_FILE,len);

     header.file_len = htonl(len);
     send(client_fd,(void *)&header,sizeof(header),0);
     
      
     while((len = fread(buf,1,sizeof(buf),file)) > 0)
           {
                  count += len ;
               if(send(client_fd,buf,len,0) <=0)
                    break;
           }

         printf("send %d bytes\n",count);

       fclose(file);
        close(client_fd);
      
     return NULL;
}
    


int main(int argc ,char * argv[])
{
  unsigned short port = 9000;
   
   int listen_fd ;
   int client_fd;
   pthread_t pth;

   struct sockaddr_in addr; //ipv4的地址结构

   struct sockaddr_in client_addr ;
   socklen_t addr_len;


   int len ;
  
   if(argc >1)
     {
         port = (unsigned short)atoi(argv[1]);
     }

  //第一步:创建一个IPV4,TCP,可以运行所有协议的SOCKET

  listen_fd = socket(PF_INET,SOCK_STREAM,0);
  if(listen_fd == -1)
   {
        perror("socket");
         return -1;
   }


   //第二步:用bind来指定端口

   memset(&addr,0,sizeof(addr));
    addr.sin_port = htons(port); //转成网络序的端口

   addr.sin_family = AF_INET; //ipv4的地址类型

   //addr.sin_addr.s_addr = inet_addr("0.0.0.0"); //bind 的sin_addr表示在哪一个网卡上有效,

   //绑定在0.0.0.0上表示这个SOCKET在所有网卡侦听

   addr.sin_addr.s_addr = INADDR_ANY; //INADDR_ANY = 0 = inet_addr("0.0.0.0")


    if(bind(listen_fd,(const struct sockaddr *)&addr,sizeof(addr)) == -1)
       {
          perror("bind");
            close(listen_fd);
          return -2;
       }

   //第三步: 通知内核里的TCP/IP协议栈,让这个SOCKET开始侦听网络上的请求

   // listen只是通知一下,通知成功立即执行后面代码

     if(listen(listen_fd,20) == -1)
       {
             perror("listen");
        close(listen_fd);
             return -3;
       }


      fprintf(stdout,"TCP File Server listen on %d\n",port);
   
      
     while(1)
       {
           memset(&client_addr,0,sizeof(client_addr));
           client_addr.sin_family = AF_INET;
           addr_len = sizeof(client_addr); //必须赋值!


           //第四步:服务器在侦听客户端请求

                printf("accept client ...\n");
           client_fd = accept(listen_fd,(struct sockaddr *)&client_addr,&addr_len);
             if(client_fd == -1)
               {
                  perror("accept");
                     continue;
               }

             fprintf(stdout,"client socket %d,addr %s,port %d\n",client_fd,
                    inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));


              pthread_create(&pth,NULL,thread_fn,(void*)client_fd);

          
       }

     printf("exit");
      close(listen_fd);

}


下载头文件定义

/*
  TCP File download define
 
  Author :Andrew Huang

 */



#ifndef __TCP_FILE_H__
#define __TCP_FILE_H__



#ifdef __cplusplus
 extern "C" {
#endif


#pragma pack(1)

typedef struct file_hdr{
    char file_name[60];
    int file_len;
}FILE_HDR;
#pragma pack()

#ifdef __cplusplus
}
#endif


#endif /* __TCP_FILE_H__ */


客户端代码
 

/*
  TCP File Client
 
  Author :Andrew Huang
 */


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdio.h>
#include <string.h>

#include "tcp_file.h"


int recv_file(int fd,char * name,int file_len)
{
    FILE * file ;
   int len,left_len = file_len;
    char buf[1024];
    file = fopen(name,"wb+");
     if(file == NULL)
        return -1;

     do{
              //计算精确接收需要多长空间

             len = (left_len < sizeof(buf)) ? left_len : sizeof(buf) ;

             len = recv(fd,buf,len,0) ;
               fwrite(buf,1,len,file);
              
                left_len -= len;
             
 
       }while(left_len>0);
     

       fclose(file);
      

      printf("recv file %s lenght %d\n",name,file_len);

}


int main(int argc ,char * argv[])
{
   unsigned short port = 9000;
   
   int sock ;
    char ipaddr[32] = "127.0.0.1";
    char buf[32] = "hello server";
    struct sockaddr_in serv_addr;
    int len;
    FILE_HDR header;

     if(argc >1)
     {
         port = (unsigned short)atoi(argv[1]);
     }

    if(argc >2)
     {
          memset(ipaddr,0,sizeof(ipaddr));
         strncpy(ipaddr,argv[2],sizeof(ipaddr)-1);
     }

    if(argc > 3)
       {
            memset(buf,0,sizeof(buf));
         strncpy(buf,argv[3],sizeof(buf)-1);
        }


   printf("connect server %s:%d,buf %s\n",ipaddr,port,buf);

  //第一步:创建一个IPV4,TCP,可以运行所有协议的SOCKET

   sock = socket(PF_INET,SOCK_STREAM,0);
   if(sock == -1)
      {
          perror("socket");
          return -1;
      }


    //第二步:对于客户端,port可用任意一个编号,如果不使用bind,协议栈会自动分配没用的端口0

    // 省略bind ....


   //第三步:用connect()去联接服务器

    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = inet_addr(ipaddr);
 
     //printf("ipaddr %s,s_addr %x\n",ipaddr,ntohl( serv_addr.sin_addr.s_addr));


     if(connect(sock,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) == -1)
        {
            perror("connect");
              close(sock);
              return -2;
        }


    //首先收下来定长的结构

        if(recv(sock,(void *)&header,sizeof(header),0)<=0)
           {
                 perror("header");
               close(sock);
                  return -3;
            }
 
           header.file_len = ntohl(header.file_len);
          //文件下载有错

           if(header.file_len < 0)
              {
                 fprintf(stderr,"file %s download failure ,return code %d\n",header.file_name,header.file_len);
                   close(sock);
                    return -4;
              }

             recv_file(sock,header.file_name,header.file_len);

             //关闭socket

            close(sock);
           
   
}


阅读(339) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~