Linux下用UDP實現檔案傳輸
阿新 • • 發佈:2018-12-17
UDP程式設計框圖
UDP協議中伺服器和客戶端的互動存在於資料的收發過程中。
進行網路資料收發的時候,伺服器和客戶端的資料是對應的:客戶端傳送資料的動作,對伺服器來說是接收資料的動作;客戶端接收資料的動作,對伺服器來說是傳送資料的動作。
實現檔案的傳輸大概分為這幾個步驟:
- 客戶端讀檔案,將內容放在client_buffer中
- 客戶端通過sendto傳送client_buffer中的資料
- 伺服器端通過recvfrom對資料進行接收,存到server_buffer中
- 將資料寫入檔案中,關閉檔案,關閉套接字
直接來程式碼:
伺服器端:
// 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一會,這個問題就解決了。
效果圖:
執行......
結果: