1. 程式人生 > >Linux下用UDP實現檔案傳輸

Linux下用UDP實現檔案傳輸

UDP程式設計框圖

                                         

UDP協議中伺服器和客戶端的互動存在於資料的收發過程中。

        進行網路資料收發的時候,伺服器和客戶端的資料是對應的:客戶端傳送資料的動作,對伺服器來說是接收資料的動作;客戶端接收資料的動作,對伺服器來說是傳送資料的動作。

     實現檔案的傳輸大概分為這幾個步驟:

  1. 客戶端讀檔案,將內容放在client_buffer中
  2. 客戶端通過sendto傳送client_buffer中的資料
  3. 伺服器端通過recvfrom對資料進行接收,存到server_buffer中
  4. 將資料寫入檔案中,關閉檔案,關閉套接字

直接來程式碼:

伺服器端:

// udp_file_server.c

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <memory.h> 
#include <stdlib.h> 

#define BUFFER_SIZE 1024

int main()
{
    int sockfd,n;
    struct sockaddr_in server,client;
	int addrlen=sizeof(struct sockaddr);
    char filename[100];
    char filepath[100];

    char *buffer;//file buffer
    int fileTrans;

    buffer = (char *)malloc(sizeof(char)*BUFFER_SIZE);
    printf("init bufferSize=%d  SIZE=%d\n",sizeof(buffer),BUFFER_SIZE);
    bzero(buffer,BUFFER_SIZE); 
    //memset(buffer,0,sizeof(buffer));
    int lenfilepath;
    FILE *fp;
    int writelength;

    if((sockfd = socket(AF_INET,SOCK_DGRAM,0))<0)
    {
        printf("socket build error!\n");
    }
    else
    {
        printf("socket build success!\n");
    }
    memset(&server,0,sizeof(server));  //清空server結構體
    server.sin_family= AF_INET;
    server.sin_addr.s_addr = htonl(INADDR_ANY);
    server.sin_port = htons(8888);

    if((bind(sockfd,(struct sockaddr*)&server,sizeof(server)))==-1)
    {
        printf("bind error!\n");
    }
    else
    {
        printf("bind success!\n");
    }
    
    while(1)
    {
	    printf("waiting....\n");
            memset(filename,'\0',sizeof(filename));
            memset(filepath,'\0',sizeof(filepath));
            lenfilepath = recvfrom(sockfd,filepath,100,0,(struct sockaddr *)&client,&addrlen);
            printf("filepath :%s\n",filepath);
            if(lenfilepath<0)
            {
                printf("recv error!\n");
				return -1;
            }
            else
            {
                int i=0,k=0;  
                for(i=strlen(filepath);i>=0;i--)  
                {  
                    if(filepath[i]!='/')      
                    {  
                        k++;  
                    }  
                    else   
                        break;    
                }  
                strcpy(filename,filepath+(strlen(filepath)-k)+1);   
            }
            printf("filename :%s\n",filename);
            fp = fopen(filename,"w");
            if(fp!=NULL)
            {
		int times = 1;
                while(fileTrans =recvfrom(sockfd,buffer,BUFFER_SIZE,0,(struct sockaddr *)&client,&addrlen))
                {
			printf("times = %d   ",times);
			times++;
                    if(fileTrans<0)
                    {
                        printf("recv2 error!\n");
                        break;
                    }

                    writelength = fwrite(buffer,sizeof(char),fileTrans,fp);

                    if(fileTrans < BUFFER_SIZE)
                    {
                        printf("finish writing!\n");
                        break;
                    }else{
			//printf("write succ! %d fileTrans=%d\n",writelength,fileTrans);
			printf("write successful!\n");
			//break;
		    }
		printf("continue\n");
                    bzero(buffer,BUFFER_SIZE); 
                    //memset(buffer,0,sizeof(buffer));
                }
                printf("recv finished!\n");
                fclose(fp);
            }
            else
            {
                printf("filename is null!\n");

            }

    }

    close(sockfd);

    return 0;

}

客戶端:

//   udp_file_client
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <memory.h> 
#include <stdlib.h>

#define BUFFER_SIZE 1024

int main()
{
    int sockcd;
    struct sockaddr_in server;
    char filepath[100];//file to translate
    int addrlen=sizeof(struct sockaddr);

    FILE *fp;
    int lenpath; //filepath length
    char *buffer;//file buffer
    int fileTrans;
    buffer = (char *)malloc(sizeof(char)*BUFFER_SIZE);
    bzero(buffer,BUFFER_SIZE); 
    //memset(buffer,0,sizeof(buffer));

    if((sockcd = socket(AF_INET,SOCK_DGRAM,0))<0)
    {
        printf("socket build error!\n");
    }
    memset(&server,0,sizeof(server));
    server.sin_family= AF_INET;
    server.sin_port = htons(8888);
    if(inet_pton(AF_INET,"127.0.0.1",&server.sin_addr)<0)
    {
        printf("inet_pton error!\n");
    }

    printf("file path:\n");
    scanf("%s",filepath);//get filepath

    fp = fopen(filepath,"r");//opne file
    if(fp==NULL)
    {
        printf("filepath not found!\n");
        return 0;

    }
    printf("filepath : %s\n",filepath);
    lenpath = sendto(sockcd,filepath,strlen(filepath),0,(struct sockaddr *)&server,addrlen);// put file path to sever 
    if(lenpath<0)
    {
        printf("filepath send error!\n");
    }
    else
    {
        printf("filepath send success!\n");
    }
    //sleep(1);
    printf("begin send data...\n");
    int times = 1;
    while((fileTrans = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)
    {
	sleep(1);  //注意這裡
	printf("times = %d   ",times);
	times++;
        //printf("fileTrans =%d\n",fileTrans);
        if(sendto(sockcd,buffer,fileTrans,0,(struct sockaddr *)&server,addrlen)<0)
        {
            printf("send failed!\n");
            break;      
        }
	else{
	    printf("send successful!\n");
	}
	if(fileTrans < BUFFER_SIZE) break;
        bzero(buffer,BUFFER_SIZE); 
        //memset(buffer,0,sizeof(buffer));  
    }
    //printf("fileTrans =%d\n",fileTrans);
    fclose(fp);

    close(sockcd);



    return 0;
}

在實現過程中,出現了這樣一種情況:

        在收發大檔案時,客戶端傳送正常,伺服器總是隻能收到前一部分檔案內容,後面的全部丟包。

在經過各種除錯之後,發現在發資料時,客戶端一直在迴圈不斷的傳送資料,傳送太快,而伺服器來不及接收 。

在每次傳送資料時,sleep一會,這個問題就解決了。

效果圖:

執行......

結果: