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);
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);
}
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);
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);
}
//printf("fileTrans =%d\n",fileTrans);
fclose(fp);
close(sockcd);
return 0;
}
在实现过程中,出现了这样一种情况:
在收发大文件时,客户端发送正常,服务器总是只能收到前一部分文件内容,后面的全部丢包。
在经过各种调试之后,发现在发数据时,客户端一直在循环不断的发送数据,发送太快,而服务器来不及接收 。
在每次发送数据时,sleep一会,这个问题就解决了。
效果图:
运行......
结果: