下载前后
上传前后
代码
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#define SER_PORT 69
#define SER_IP "192.168.124.116"
int do_download(int cfd, struct sockaddr_in sin)
{
char filename[20] = "";
printf("请输入要下载的文件名>>");
scanf("%s",filename);
while(getchar() != '\n');
//组下载请求包
char rq_buf[128] = "";
short *p1 = (short*)rq_buf;
*p1 = htons(1); //操作码 下载为1
char *p2 = rq_buf+2;
strcpy(p2, filename); //文件名
char *p3 = p2+strlen(filename)+1;
strcpy(p3, "octet"); //模式
int rq_len = 2+strlen(p2)+1+strlen(p3)+1;
//给服务器发送一个下载请求
if( sendto( cfd, rq_buf, rq_len, 0, (struct sockaddr*)&sin, sizeof(sin) ) <0){
fprintf( stderr, "line:__%d__", __LINE__);
perror("sendto");
return -1;
}
printf("sendto download 请求成功 __%d__\n",__LINE__);
struct sockaddr_in cin; //存储临时地址信息
int addrlen = sizeof(cin);
char tempbuf[516] = "";
for(int i=1; ;i++){
memset( tempbuf, 0, 516);
int res = recvfrom( cfd, tempbuf, sizeof(tempbuf), 0, (struct sockaddr*)&cin, &addrlen) ; //接收数据包
if(res <0){
fprintf(stderr, "__%d__", __LINE__);
perror("recvform");
break;
}
//判断报错+写文件
short *data = (short*)tempbuf;
short num = ntohs(*(data+1));
char *wrt = tempbuf+4;
if(3 == ntohs(*data) ){
int fd = open(filename, O_CREAT|O_RDWR|O_APPEND, 0666); //创建接收的文件
if(fd <0){
fprintf(stderr, "line:__%d__",__LINE__);
perror("open");
return -1;
}
int ret = write(fd, wrt, res-4);
if(ret<0 || ret!=res-4){
perror("write err");
return -2;
}
ret = close(fd);
if(ret <0){
perror("close err");
return -2;
}
}
else if(5 == ntohs(*data)){
printf("Error message:%s\n",tempbuf+4);
return -1;
}
else{
printf("操作码 err\n");
return -1;
}
//发回ACK
char ack[4] = "";
short *a1 = (short*)ack;
*a1 = htons(4);
short *a2 = a1+1;
*a2 = htons(num);
if( (sendto(cfd, ack, 4, 0, (struct sockaddr*)&cin, addrlen)) <0){
fprintf(stderr, "__%d__",__LINE__);
perror("sendto");
return -1;
}
printf("sendto ack%d success__%d__\n",i,__LINE__);
//若该数据包数据长度小于512,则结束
if((res-4)<512){
printf("传输结束\n");
break;
}
}
return 0;
}
int do_upload(int cfd, struct sockaddr_in sin)
{
char filename[20] = "";
printf("请输入要上传的文件名>>");
scanf("%s",filename);
while(getchar() != '\n');
//组上传请求包
char rq_buf[128]="";
short *p1 = (short*)rq_buf;
*p1 = htons(2); //操作码 上传为2
char *p2 = rq_buf+2;
strcpy(p2, filename); //文件名
char *p3 = p2+strlen(filename)+1;
strcpy(p3, "octet"); //模式
int rq_len = 2+strlen(p2)+1+strlen(p3)+1;
//给服务器发送一个上传请求
if(sendto(cfd, rq_buf, rq_len, 0,(struct sockaddr*)&sin, sizeof(sin)) <0){
fprintf(stderr, "__%d__",__LINE__);
perror("sendto");
return -1;
}
printf("senfto upload 请求成功__%d__\n",__LINE__);
struct sockaddr_in cin; //存储临时地址信息
int addrlen = sizeof(cin);
char ack_buf[4];
memset(ack_buf, 0, sizeof(ack_buf));
//接收第一个ACK包
int res = recvfrom(cfd, ack_buf, sizeof(ack_buf), 0, (struct sockaddr*)&cin, &addrlen);
if(res <0){
fprintf(stderr,"__%d__",__LINE__);
perror("recvfrom");
return -1;
}
short *ack_p1 = (short*)ack_buf;
short *ack_p2 = ack_p1+1;
printf("recv ack_bug success __%d__\n",__LINE__);
if(4 != ntohs(*ack_p1) ){
printf("操作码:%d 块编号:%d ;ack err",ntohs(*ack_p1),ntohs(*ack_p2));
return -1;
}
printf("recv ack success __%d__\n",__LINE__);
//开始发送数据包
int fd = open(filename,O_RDONLY);
if(fd <0){
fprintf(stderr, "__%d__",__LINE__);
perror("open");
return -1;
}
char temp[516]="";
//组合数据包
short *data_p1 = (short*)temp;
*data_p1 = ntohs(3);
short *data_p2 = data_p1+1;
*data_p2 = ntohs(0);
char *data_p3 = (char*)p2+1;
//循环获取文件内容,进行数据包组合
for(int i=1; ; i++){
memset(temp+4, 0, 512);
*data_p2 = ntohs(i);
int ret =read(fd, temp+4, 512);
if(ret <0){
perror("read");
return -3;
}
if(sendto(cfd, temp, 516, 0, (struct sockaddr*)&cin, addrlen)<0){
fprintf(stderr,"__%d__",__LINE__);
perror("sendto");
return -1;
}
printf("sendto upload %s databag success __%d__\n",filename,__LINE__);
//清空ACK包并重新获取
memset(ack_buf, 0, 4);
res = recvfrom(cfd, ack_buf, sizeof(ack_buf), 0, (struct sockaddr*)&cin, &addrlen);
if(res <0){
fprintf(stderr, "__%d__",__LINE__);
perror("recvfrom");
return -1;
}
short *new_ack_p1 = (short*)ack_buf;
short *new_ack_p2 = new_ack_p1+1;
if(4 != ntohs(*new_ack_p1) && i-1 != ntohs(*new_ack_p2)){
printf("操作码:%d 块编号:%d ;ack err\n",ntohs(*new_ack_p1),ntohs(*new_ack_p2));
perror("ack err");
return -1;
}
printf("recv ack_bug%d success __%d__\n",i,__LINE__);
if(ret<512){
printf("传输结束\n");
if(close(cfd) <0){
perror("close");
return -2;
}
break;
}
}
return 0;
}
int main(int argc, const char *argv[])
{
//获取IP
if(argc <2){
printf("请输入要连接的IP:");
return -1;
}
//创建报式套接字
int cfd = socket(AF_INET, SOCK_DGRAM, 0);
if(cfd <0){
fprintf(stderr, "__%d__",__LINE__);
perror("socket");
return -1;
}
printf("socket success __%d__\n",__LINE__);
//服务器的地址信息结构体--->port:69
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(69);
sin.sin_addr.s_addr = inet_addr(argv[1]);
//程序界面
int loop =1;
int choose =0;
while(loop){
printf("------------------\n");
printf("------1.下载------\n");
printf("------2.上传------\n");
printf("------3.退出------\n");
printf("------------------\n");
printf("请输入>>");
scanf("%d",&choose);
while(getchar() != '\n');
switch(choose){
case 1:
do_download(cfd,sin);
break;
case 2:
do_upload(cfd,sin);
break;
case 3:
loop = 0;
break;
default :
printf("输入错误,请重新输入\n");
}
}
close(cfd);
return 0;
}