linux下大文件分包传输

实验说明:

Linux下基于TCP协议的大文件传输程序
【实验内容】
通过Linux C编程,设计一个基于TCP协议的大文件传输系统,实现服务器端向客户端的大文件的传输
【实验要求】
(1)大文件的传输。对于比较大的文件,应该进行分包操作,以防止占用过多的内存,导致文件发送
失败,实验中每次最多传输1024个字符;
(2)用户根据参数输入选择传输的文件和传输位置;
(3)发送端和接收端分别显示文件传输相应的信息,包括:对方IP地址,当前已写(读)文件长度等;
(4)对于Ctrl+C命令以及服务器提前关闭的特殊情况给出响应(如:显示信息)

代码:

client.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#define PORT 6000
#define LISTENQ 20
#define BUFFSIZE 1024
#define FILE_NAME_MAX_SIZE 512
extern void sig_proccess(int signo);
extern void sig_pipe(int signo);
static int s;

int main(int argc, char **argv[])
{
    int clientfd;
    signal(SIGINT, sig_proccess);
    signal(SIGPIPE, sig_pipe);
    char file[FILE_NAME_MAX_SIZE];
    if(argc!=2)
    {
        fprintf(stderr,"用法错误:./client <IP_Address>\n");
        exit(1);
    }
    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(argv[1],&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);
    }
    else{
    //recv file imformation
    char buff[BUFFSIZE]={0};
    char filename[FILE_NAME_MAX_SIZE]={0};
    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));
        if (strlen(filename)==0 )
        printf("准备接收文件不存在!\n");
else{
    printf("准备从 : %s 接收文件 %s \n",argv[1],filename); 
    printf("请输入要接收的文件名(当前目录下)或文件地址:");
    scanf("%s",&file);
    //recv file
    FILE *fd=fopen(file,"wb+");
    if(fd==NULL)
    {
        perror("open");
        exit(1);
    }
    else
        {bzero(buff,BUFFSIZE);
        int total=0;
    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<length)
        {
            perror("write");
            exit(1);
        }
        total=total+length;
        printf("已接受的长度:%d,总共接收的长度:%d\n",length,total);
        bzero(buff,BUFFSIZE);
    }
    printf("接收来源于 %s的文件%s  已完成!\n",argv[1],filename);}
    fclose(fd);}}
    close(clientfd);
    return 0;
}

server.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>   
#include <sys/stat.h>
#include <signal.h>
#define PORT 6000
#define LISTENQ 20
#define BUFFSIZE 1024
#define FILE_NAME_MAX_SIZE 512
extern void sig_proccess(int signo);
extern void sig_pipe(int signo);
static int s;

int main(int argc, char **argv[])
{
    signal(SIGINT, sig_proccess);
    signal(SIGPIPE, sig_pipe);
    //Input the file name
    char filename[FILE_NAME_MAX_SIZE];
    bzero(filename,FILE_NAME_MAX_SIZE);


    //Create socket
    int sockfd,connfd;
    struct sockaddr_in svraddr,clientaddr;
    bzero(&svraddr,sizeof(svraddr));

    svraddr.sin_family=AF_INET;//Ipv4网络协议
    svraddr.sin_addr.s_addr=htonl(INADDR_ANY);//本地地址
    svraddr.sin_port=htons(PORT);//服务器端口

    sockfd=socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0)
    {
        perror("socket");
        exit(1);
    }

    //bind  
    if(bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr))<0)
    {
        perror("bind");
        exit(1);
    }

    //listen
    if(listen(sockfd,LISTENQ)<0)
    {
        perror("listen");
        exit(1);
    }

    while(1)
    {
        socklen_t length=sizeof(clientaddr);

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

        printf("请输入要传输的文件名(当前目录下)或文件地址:");
            scanf("%s",&filename);
            //getchar();
        //read file 
        FILE *fd=fopen(filename,"rb");
        if(fd==NULL)
        {
            printf("文件 :%s 没有找到!\n",filename);

        }
        else 
        {//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);
        }

                         struct stat buf ;
                        if ( stat( filename, &buf ) < 0 )
                       {
                         perror( "stat" );
                          return ;
                         }
                         printf("文件大小:%d\n", buf.st_size );
            bzero(buff,BUFFSIZE);
            int file_block_length=0;
                        int total=0;
            while((file_block_length=fread(buff,sizeof(char),BUFFSIZE,fd))>0)//(BUFFSIZE<buf.st_size ?BUFFSIZE:buf.st_size)
            {  
                                total=total+file_block_length;
                printf("发送文件大小:%d,总共发送了:%d\n",file_block_length,total);
                if(send(connfd,buff,file_block_length,0)<0)
                {
                    perror("Send");
                    exit(1);
                }
                bzero(buff,BUFFSIZE);   
            }
            fclose(fd);
            printf("传输来源于 %s 端口号为%d的文件 %s已完成! \n",
                        inet_ntop(AF_INET, &clientaddr.sin_addr, buff, sizeof(buff)),  ntohs(clientaddr.sin_port), filename );
        }
        close(connfd);
    }
    close(sockfd);
    return 0;
}

tcp_process.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>   
#include <sys/stat.h>
#include <signal.h>
static struct iovec*vs = NULL, *vc=NULL;
void sig_proccess(int signo){
    printf(" catch a exit signal\n");

    free(vc);
    free(vs);
    _exit(0);


}


void sig_pipe(int sign)
{

    printf("catch a sigpipe signal\n");

    free(vc);
    free(vs);
    _exit(0);
}

Makefile:

all:client server                   #all规则,它依赖于client和server规则

client:tcp_process.o client.o   #client规则,生成客户端可执行程序
    gcc -o client tcp_process.o client.o
server:tcp_process.o server.o   #server规则,生成服务器端可执行程序
    gcc -o server tcp_process.o server.o    
tcp_process.o:                      #tcp_process.o规则,生成tcp_process.o
    gcc -c tcp_process.c -o tcp_process.o
clean:                              #清理规则,删除client、server和中间文件
    rm -f client server *.o

猜你喜欢

转载自blog.csdn.net/qq_34062105/article/details/80263877