基于UDP客户端下载与上传
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#define ERR_MSG(msg) do{\
fprintf(stderr,"line:%d",__LINE__);\
perror(msg);\
}while(0)
#define IP "192.168.0.172"
#define PORT 69
int main(int argc, const char *argv[])
{
//创建报式套接字
int cfd = socket(AF_INET,SOCK_DGRAM,0);
if(cfd < 0){
ERR_MSG("socket");
return -1;
}
printf("socket success\n");
//服务器地址信息
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.s_addr = inet_addr(IP);
//判断是下载还是上传
int flag = 0;
int a= 0;
printf("请输入是下载还是上传(1:下载,2:上传):\n");
scanf("%d",&a);
if(a == 1){
flag = 1;
}else if(a == 2){
flag = 0;
}
//下载
if(flag == 1){
//向这服务器发送下载请求
char buf[516] = "";
char filename[20] = "";
printf("输入要下载的文件名:");
scanf("%s",filename);
memset(buf,0,sizeof(buf));
int size = sprintf(buf,"%c%c%s%c%s%c",0x00,0x01,filename,0,"octet",0);
if(sendto(cfd,buf,size,0,(struct sockaddr *)&sin,sizeof(sin)) < 0){
ERR_MSG("sendto");
return -1;
}
printf("sendto success\n");
struct sockaddr_in ser_sin;//ser_sin表示服务器回复时的IP和随机端口
socklen_t addrlen = sizeof(ser_sin);
ssize_t res = 0;
int fd = 0;
int size_ACK = 0;
fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
while(1){
//接受服务器发送的数据包
memset(buf,0,sizeof(buf));
res = recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr *)&ser_sin,&addrlen);
if(res < 0){
ERR_MSG("recvfrom");
return -1;
}
printf("[%s:%d]\n",inet_ntoa(ser_sin.sin_addr),ntohs(ser_sin.sin_port));
//如果接收的是数据包
//提取数据包的数据(buf+4),另存到文件中
if(buf[1] == 0x03 && (res-4) >= 512){
write(fd,buf+4,res-4);
//给服务器回复ACK-->组ACK包,快编号与接收到的数据包的快编号一致
size_ACK = sprintf(buf,"%c%c%c%c",0x00,0x04,buf[2],buf[3]);
if(sendto(cfd,buf,size_ACK,0,(struct sockaddr *)&ser_sin,sizeof(ser_sin)) < 0){
ERR_MSG("sendto");
return -1;
}
}else if(buf[1] == 0x03 && (res-4) < 512){
write(fd,buf+4,res-4);
printf("下载完成\n");
break;
}else if(buf[1] == 0x05){
printf("%c%c\n",buf[2],buf[3]);
printf("%s\n",buf+4);
break;
}
}
}else if(flag == 0){
//向这服务器发送上传请求
char buf[516] = "";
char filename[20] = "";
printf("1\n");
printf("输入要上传的文件名:");
scanf("%s",filename);
memset(buf,0,sizeof(buf));
int size = sprintf(buf,"%c%c%s%c%s%c",0x00,0x02,filename,0,"octet",0);
if(sendto(cfd,buf,size,0,(struct sockaddr *)&sin,sizeof(sin)) < 0){
ERR_MSG("sendto");
return -1;
}
printf("sendto success\n");
struct sockaddr_in ser_sin;//ser_sin表示服务器回复时的IP和随机端口
socklen_t addrlen = sizeof(ser_sin);
ssize_t res = 0;
int fd = 0;
int size_ACK = 0;
fd = open(filename,O_RDONLY,0666);
char r_buf[512] = "";
int read_res = 0;
char buf_ACK[4] = "";
char g = 0x01;
while(1){
//接受服务器回复的ACK包
memset(buf_ACK,0,sizeof(buf_ACK));
memset(buf,0,sizeof(buf));
res = recvfrom(cfd,buf_ACK,sizeof(buf_ACK),0,(struct sockaddr *)&ser_sin,&addrlen);
if(res < 0){
ERR_MSG("recvfrom");
return -1;
}
//printf("[%s:%d]\n",inet_ntoa(ser_sin.sin_addr),ntohs(ser_sin.sin_port));
printf("%d%d%d%d\n",buf_ACK[0],buf_ACK[1],buf_ACK[2],buf_ACK[3]);
//根据服务器回复的ACK包封装数据包
buf_ACK[1] = 0x03;
buf_ACK[3] = buf_ACK[3]+1;
buf[0] = buf_ACK[0];
buf[1] = buf_ACK[1];
buf[2] = buf_ACK[2];
buf[3] = buf_ACK[3];
char *p = buf+4;
read_res = read(fd,r_buf,sizeof(r_buf));
strcat(p,r_buf);
printf("buf =%ld\n",sizeof(buf));
if(sendto(cfd,buf,read_res+4,0,(struct sockaddr *)&ser_sin,sizeof(ser_sin)) < 0){
ERR_MSG("sendto");
return -1;
}
printf("sendto success\n");
if(read_res < 512){
break;
}
}
}
close(cfd);
return 0;
}