Socket网络程序设计(3) ———— 利用tcp完成文件传输的设计和实现

用TCP/TP进行网际互连(3)

———— 利用tcp完成文件传输的设计和实现

1、要求介绍

利用循环面向连接的模型完成固定文件的传输
由固定文件扩展成手动输入或选择文件
——废话少说,直接上代码——

2、实现代码

  • 服务器:
1.初始化服务器端的socket:)
   int sockfd,connfd;
    struct sockaddr_in svraddr,clientaddr;
    bzero(&svraddr,sizeof(svraddr));

    svraddr.sin_family=AF_INET;
    svraddr.sin_addr.s_addr=htonl(INADDR_ANY);
    svraddr.sin_port=htons(PORT);

    sockfd=socket(AF_INET,SOCK_STREAM,0);

(2.进行绑定:)
    if(bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr))<0)
    {
        perror("bind");
        exit(1);
    }
(3.变为被动模式,进行监听)
   //listen
    if(listen(sockfd,LISTENQ)<0)
    {
        perror("listen");
        exit(1);
    }
(4.循环等待实现文件的传输)
    while(1)
    {
        socklen_t length=sizeof(clientaddr);

        //accept
        connfd=accept(sockfd,(struct sockaddr*)&clientaddr,&length);
        if(connfd<0)
        {
            perror("connect");
            exit(1);
        }

        //send file imformation
        char buff[BUFFSIZE];
        int count;
        bzero(buff,BUFFSIZE);
        strncpy(buff,filename,strlen(filename)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(filename));
        count=send(connfd,buff,BUFFSIZE,0);
        if(count<0)
        {
            perror("Send file information");
            exit(1);
        }

        //read file 
        FILE *fd=fopen(filename,"rb");
        if(fd==NULL)
        {
            printf("File :%s not found!\n",filename);
                    }
        else 
        {
            bzero(buff,BUFFSIZE);
            int file_block_length=0;
            while((file_block_length=fread(buff,sizeof(char),BUFFSIZE,fd))>0)
            {
                printf("file_block_length:%d\n",file_block_length);
                if(send(connfd,buff,file_block_length,0)<0)
                {
                    perror("Send");
                    exit(1);
                }
                bzero(buff,BUFFSIZE);   
            }
            fclose(fd);
            printf("Transfer file finished !\n");
        }
        close(connfd);
    }
  • 客户端
主函数:
  int main(int argc, char **argv[])
{
    int clientfd;
    //连接
    clientfd=connectTCP("127.0.0.1",PORT);
    //接收信息
    recvTCP(clientfd);
    //关闭
    close(clientfd);
    return 0;
}
  (可以看出整个主函数变得非常简洁)

//connectTCP函数封装了TCP的连接过程
  int connectTCP(const char *host, const char *port){
    int clientfd;
    struct sockaddr_in clientaddr;
    bzero(&clientaddr,sizeof(clientaddr));  

    clientaddr.sin_family=AF_INET;
    clientaddr.sin_addr.s_addr=htons(INADDR_ANY);
    clientaddr.sin_port=htons(0);

    clientfd=socket(AF_INET,SOCK_STREAM,0);

    if(clientfd<0)  
    {
        perror("socket");
        exit(1);
    }

    if(bind(clientfd,(struct sockaddr*)&clientaddr,sizeof(clientaddr))<0)
    {
        perror("bind");
        exit(1);
    }

    struct sockaddr_in svraddr;
    bzero(&svraddr,sizeof(svraddr));
    if(inet_aton(host,&svraddr.sin_addr)==0)
    {
        perror("inet_aton");
        exit(1);
    }
    svraddr.sin_family=AF_INET;
    svraddr.sin_port=htons(port);

    socklen_t svraddrlen=sizeof(svraddr);
    if(connect(clientfd,(struct sockaddr*)&svraddr,svraddrlen)<0)   
    {
        perror("connect");
        exit(1);
    }
    return clientfd;
}

//recvTCP封装了接收文件的过程
  void recvTCP(int clientfd){
    //recv file imformation
    char buff[BUFFSIZE];
    char filename[FILE_NAME_MAX_SIZE];
    int count;
    bzero(buff,BUFFSIZE);

    count=recv(clientfd,buff,BUFFSIZE,0);
    if(count<0)
    {
        perror("recv");
        exit(1);
    }
    strncpy(filename,buff,strlen(buff)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buff));

    printf("Preparing recv file : %s  \n",filename);    

    //recv file
    FILE *fd=fopen(filename,"wb+");
    if(NULL==fd)
    {
        perror("open");
        exit(1);
    }
    bzero(buff,BUFFSIZE);

    int length=0;
    while(length=recv(clientfd,buff,BUFFSIZE,0))
    {
        if(length<0)
        {
            perror("recv");
            exit(1);
        }
        int writelen=fwrite(buff,sizeof(char),length,fd);
        if(writelen"write");
            exit(1);
        }
        bzero(buff,BUFFSIZE);
    }
    printf("Receieved file:%s  finished!\n",filename);
    fclose(fd);
}

3、代码分析

  • 首先在服务器端利用循环面向连接的模型进行文件的传输,实现向每一个接入的客户端发送文件的服务。文件名可以手动输入来选择文件。
  • 客户端程序进行相应的socket连接。进行封装之后,简化了主函数,使主函数变得简洁清晰了很多,通过调用connectTCP进行socket函数连接的封装,方便之后的扩展,如添加一个基于UDP协议的传输服务。

4、运行效果

  • 服务器端启动,选择要传输的文件:
    Socket网络程序设计(3) ———— 利用tcp完成文件传输的设计和实现_第1张图片

  • 客户端连接:
    Socket网络程序设计(3) ———— 利用tcp完成文件传输的设计和实现_第2张图片

  • 测试,当传输稍大文件时:
    Socket网络程序设计(3) ———— 利用tcp完成文件传输的设计和实现_第3张图片

附上我的测试成功的实验代码:
https://github.com/KevinBetterQ/Network-programming/tree/master/TCP_file

你可能感兴趣的:(Socket网络程序设计)