网络间通信socket传输任意格式任意大小的文件

24 篇文章 0 订阅

http://blog.csdn.net/hdw10/article/details/7497760

      最近看到很多网友写的socket程序,试验了几个,发送"Hello,world"时都没有问题,但在传输较大文件,比如一个200M的文件时,都不能成功,即使成功了,server端也存在保存的问题, 有的是乱码,也有文件大小不对的情况,这两天工作不忙,我也草草写了一些代码,实现了可以传输任意格式任意大小的文件,几位同事帮我一起做了测试,传送几百M的文件速度还是很快的,而且也没有丢数据的问题。  代码原理很简单,所以也没有做注释,大家可以把代码copy下来,自己把玩一下。现在我跟同事之间传送datasheet,都在使用我的程序, 其实我也是个入行不深的人,代码并没有经过优化,很多printf() 是多余的,也有的地方写的很麻烦。希望大家给以批评,给以帮助。


              由于 网络接口MTU的限制(一般mtu为1500),大些的文件只能分多次发送,这样就有几个问题:分几次发送?一次发送多大? 保存端的怎么保存?

我的办法是:通过定义一个shouldoplen,来说明一次操作需要操作的长度,如果要发送的文件较小(跟buf相比),shouldoplen 就是读取的文件大小,如果文件较大,需要多次发送,那么shouldoplen 就是buf  的长度,通过多次读取,发送, 直到发送出去的总长度oplencount  等于文件的大小,这时一个文件就算完整发送成功了。


编译时:  

    gcc  socket_server.c -lpthread  -o server

    gcc  socket_client.c -o client


使用时:


在一端打开server

       #./server


令一端使用client   

     #./client ./han/docunt/Linux_dd.pdf  Linux_dd.pdf


这样就把./han/docunt/Linux_dd.pdf 这就文件  发送server端,保存名为Linux_dd.pdf        


当然,前提是在sock_client.c  中的把目的IP改为你要连接的目的IP。


***********************这是data.h****************

#ifndef DATA_H
#define DATA_H

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<fcntl.h>
#include<signal.h>
#include<pthread.h>
#include<sys/socket.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netinet/in.h>


#include "data.h"


typedef  unsigned int uint;

struct data{


    char filename[30];              //要发送的文件名(可含路径)

    char filesavename[30];    //要保存的文件名(可含路径)
    
    uint filelen;                        //文件从字节数

    uint shouldoplen;             //一次要操作的字节数
    
    uint oplencount;                // 操作的字节总数

    char filebuf[1300];                //由于mtu为1500,在不改动mtu的情况下,1300没有问题。


    
};


struct data_return {
        
    int writelen;                           //server端保存文件时,一次写的长度
    
    int writelencount;                //写的总数
    
    int recvlen;                             //一次接受到的长度
};





#endif





***********************这是sock_sever 端********************************


#include "data.h"



int sockid;

pthread_t tid;


int fileopen;


__sighandler_t f_quit(void)
{

    printf("\nserver closed right now!!\n");
    close(sockid);
    close(fileopen);
    exit(0);


}


struct thread_para{

    int sockid;
    
    struct sockaddr_in addr;

    struct sockaddr_in fromaddr;

    struct data datarecv;
};


int main(int argc,char* argv[])
{
    

    signal(SIGINT,(__sighandler_t)f_quit);


    struct thread_para thread_do;

    memset(&thread_do,0,sizeof(thread_do));

    

    sockid = socket(AF_INET,SOCK_STREAM,0);
    
    if(sockid == -1)
        printf("socker create error!"),exit(-1);

    printf("sockid = %d\n",sockid);

    struct sockaddr_in addr;    
    
    addr.sin_family = AF_INET;

    addr.sin_port = htons(8888);

    addr.sin_addr.s_addr = INADDR_ANY;

    int r = bind(sockid,(struct sockaddr*)&addr,sizeof(addr));

    if(r<0) 
        printf("bind error!,r=%s\n",strerror(errno)),exit(-1);
    
    printf("bind success!\n");



    if((r = listen(sockid,10))<0)
        printf("listen error!,r=%s\n",strerror(errno)),exit(-1);
    
    printf("listen successfully!\n");


    int fd,writelen,writelencount,recvlen,opnumber;
    
    struct sockaddr_in fromaddr;


    socklen_t len = sizeof(fromaddr);


    void* handler(void*);


    while(1){
        
        
        if( (fd = accept(sockid,(struct sockaddr*)&fromaddr,&len)) < 0 ){

            printf("accept error,errno = %s\n",strerror(errno)),exit(-1);
        } 

    
        printf("accept successfuluy!,new sockid=%d\n",fd);
    
        memset(&thread_do,0,sizeof(thread_do));
    
        thread_do.sockid = fd;

        thread_do.fromaddr = fromaddr;
    
        pthread_create(&tid,NULL,handler,&thread_do);


    }

}

void* handler(void* p)
{

    struct thread_para * thread_do = p;


    int writelen,writelencount,recvlen,opnumber;

    writelen = 0;

    writelencount = 0;    
    
    recvlen = 0;

    opnumber = 1;

    printf(" there are the data from %s :\n",inet_ntoa(thread_do->fromaddr.sin_addr) );
    

    do{


        memset(&thread_do->datarecv,0,sizeof(thread_do->datarecv));
    
        recvlen = recv( thread_do->sockid,&thread_do->datarecv,sizeof(thread_do->datarecv)-1,0);        
    
        if(recvlen<0) 
            
            printf("recv error!,errro=%s\n",strerror(errno)),exit(-1);

        else if(recvlen == 0 ) 
        
            printf(" client has closed!\n");
        
        else
    
            printf("the filename from client:\n\t%s\n",thread_do->datarecv.filename);
        
            printf("the file save name:\n\t%s\n",thread_do->datarecv.filesavename);
    
            printf("the filelen =%d,the recvlen=%d,the filebuf = %d\n",thread_do->datarecv.filelen,recvlen,sizeof(thread_do->datarecv.filebuf)-1 );

            printf("the shouldoplen = %d\n",thread_do->datarecv.shouldoplen);

            printf("the oplencount = %d\n",thread_do->datarecv.oplencount);
    

            umask(0);

            int fileopen = open((const char*)thread_do->datarecv.filesavename,O_RDWR | O_CREAT | O_APPEND, S_IRWXU | S_IRWXG | S_IROTH );    
    
            if(fileopen<0){

                printf("fileopen error!,%s\n",strerror(errno)),exit(-1);
        
            }

            printf("file %s create and open successfully!\n",thread_do->datarecv.filesavename);



            if( (  writelen =  write(fileopen,thread_do->datarecv.filebuf,thread_do->datarecv.shouldoplen)  ) <0 ){

                printf("write error!\n"),exit(-1);
            }
             
            writelencount  += writelen;

            printf(" opnumber = %d,writelen=%d,writelencount=%d\n \n",opnumber++,writelen,writelencount);

            struct data_return data_r;
    
            data_r.writelen = writelen;
    
            data_r.writelencount = writelencount;    
        
            data_r.recvlen = recvlen;

            write(thread_do->sockid, &data_r ,sizeof(data_r));
        
            close(fileopen);
    
            }while( writelencount != thread_do->datarecv.filelen );

        

}    





***********************************这是sock_client 端*******************************


#include "data.h"


int sockid;



__sighandler_t f_quit(void)
{

        printf("\n client closed right now!!\n");
        close(sockid);
 
        exit(0);

  
}


int main(int argc,char* argv[])
{

    signal(SIGINT,(__sighandler_t)f_quit);

    sockid = socket(AF_INET,SOCK_STREAM,0);
    
    if(sockid==-1){
    
        printf("socket create error!"),exit(-1);
    
    }
    
    struct sockaddr_in addr;

    memset(&addr,0,sizeof(addr));

    addr.sin_family = AF_INET;

    addr.sin_port = htons(8888);

    inet_aton("192.168.10.52",&addr.sin_addr);

    
    int r = connect(sockid,(struct sockaddr*)&addr,sizeof(addr));

    if(r<0)printf("connect error!\n"),exit(-1);

    printf("connect success!  \n");

    struct data datasent;
    
    memset(&datasent,0,sizeof(datasent));
    
    struct  data_return data_r;

    memset(&data_r,0,sizeof(data_r));

    strcpy(datasent.filename, argv[1]);
    
    strcpy(datasent.filesavename,argv[2]);

    int fd  = open(datasent.filename,O_RDWR);    

    if(fd<0){
    
        printf("open %s failed!\n",datasent.filename),exit(-1);
    }
    
    datasent.filelen = lseek(fd,0,SEEK_END);
    
    lseek(fd,0,SEEK_SET);

    printf("open file %s success!,the fd = %d,file length  = %d\n",datasent.filename,fd,datasent.filelen);

    datasent.oplencount = 0;

    int opnumber = 1;

    do{
    
        lseek(fd,datasent.oplencount,SEEK_SET);


        if( (datasent.filelen - datasent.oplencount ) >= ( sizeof(datasent.filebuf) - 1 ) ){                    //  比较: ( filelen - oplencount   ) 与  filebuf 的大小        
    
            datasent.shouldoplen = sizeof(datasent.filebuf) - 1 ;                                                             //通过比较,确定出shouoplen的值
        }

        else{
            datasent.shouldoplen = datasent.filelen -datasent.oplencount;    
        }

        memset(&datasent.filebuf,0,sizeof(datasent.filebuf));

        readdata(fd,&datasent,datasent.shouldoplen);

        datasent.oplencount += datasent.shouldoplen;

        sentdata(datasent);

        printf(" opnumber = %d,shouldoplen = %d ,datasent.oplencount = %d \n",opnumber++,datasent.shouldoplen,datasent.oplencount);

        read(sockid,&data_r,sizeof(data_r));
    
        printf("server info:recvlen = %d, writelen = %d, writelencount = %d \n\n",data_r.recvlen,data_r.writelen,data_r.writelencount);


        } while( datasent.filelen > datasent.oplencount );


        close(sockid);

        close(fd);                
                                
}

int readdata(int fd,struct data* datasent,int len)
{
    int readlen;

    if((readlen = read( fd,datasent->filebuf,len ) )<0){                                                            //通过len来确定一次要读多少
        
        printf("%m\n"),exit(-1);
    }

    printf("read %s successfully ! readlen=%d\n",datasent->filename,readlen);

}


int sentdata(struct data datasent)
{

    int sendlen;    

    if((sendlen = send( sockid,&datasent,sizeof(datasent)-1,0 ))<0){
    
        printf("write error ,writelen=%d, sizeof(datasent): %d, error: %s\n",sendlen, sizeof(datasent), strerror(errno));
    
        exit(-1);
    }

    printf("file %s send successfully!,sendlen=%d\n",datasent.filename,sendlen); 


}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值