代码:
#include <stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<string.h>
#include<unistd.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#define err_msg(pg)do{\
fprintf(stderr,"line:__%d__",__LINE__);\
perror(pg);\
}while(0);
//将客户端的端口与ip地址宏定义
#define cil_port 8856 //客户端的端口
#define cil_ip "192.168.8.168" //客户端ip地址
//将目标服务器的端口和ip地址宏定义
#define ser_port 69 //服务器端口
#define ser_ip "192.168.8.132" //服务器ip地址
int upload(int fd,struct sockaddr_in sin);
//上传函数
int upload(int fd,struct sockaddr_in sin)
{
/**********************************开始定义读写请求服务器下载包的协议数组*******************************************/
//定义一个字符数组 用于发送数据包
char buf[516]="";
//根据下载包协议定义数组
short* p1=(short*) buf; //定义一个short类型的指针指向数组的首地址 并将他类型转换为short
*p1=htons(2); //将协议中的操作码的读权限所对应的1填入指针中******操作码********
char* p2=(char*)(p1+1); //定义一个char 类型的指针指向数组中文件名所对应的位置****文件名****
strcpy(p2,"./1.c"); //将下载服务器中的文件名5.png填到里面 因为strcpy自动补\0,所以后面
//后面不用指针指向请求服务器下载下载包协议中0的位置******文件名*******
char* p3=p2+strlen(p2)+1; //strlen不计算字符串的\0位 但是请求下载下载包协议中有0位 所以加1*****模式**
strcpy(p3,"octet"); //将请求下载包协议中的模式放入数组的p3位置
int tlern=2+strlen(p2)+1+strlen(p3)+1;
//因为strcpy将字符串复制后自动补\0
//所以请求下载协议包最后一位不补\0;
/********************************读写请求服务器下载下载包的协议数组至此定义完毕**************************************/
/*****************************开始定义服务器返回客户端的数据包协议数组******************************************/
char str[4]="";
/****************************返回客户端的数据包协议数组定义完毕**************************************************/
/*****************************开始定义客户端发送给服务器的数据包协议数组******************************************/
char arr[516]="";
/****************************客户端发送给服务器的数据包协议数组定义完毕**************************************************/
socklen_t size=sizeof(sin);
//发送请求上传数据
if(sendto(fd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
err_msg("sendto");
return -1;
}
int value=1;
ssize_t count=0;
ssize_t cond=0;
//打开一个文件接受数据
int fp=open("./1.c",O_RDONLY);
if(fp<0)
{
err_msg("open");
return -1;
}
int seclect=0;
while(1)
{
//接收服务器发送的允许下载的回应包
if((count=recvfrom(fd,str,sizeof(str),0,(struct sockaddr*)&sin,&size))<0)
{
err_msg("recvfrom");
return -1;
}
//将数据包的块编号由str获取到的数值放入arr中
arr[3]=str[3];
short* q1=(short*)arr;
*q1=htons(3);
//读取需要上传的文件的数据
if((cond=read(fp,arr+4,512))<0)
{
err_msg("read");
return -1;
}
if(0==cond)
{
break;
}
//将读取的数据上传给服务器
if(sendto(fd,arr,cond+4,0,(struct sockaddr*)&sin,size)<0)
{
err_msg("sendto");
return -1;
}
//下载包<516下载结束退出循环
if(0==cond)
{
printf("传输完成,请继续选择功能\n");
break;
}
//将下载包的操作码改为回应包协议
}
return 0;
}
int main(int argc, const char *argv[])
{
//创建客户端套接字文件
int fd=socket(AF_INET,SOCK_DGRAM,0); //因为用的是udp传输所以创建的是报式套接字文件
if(fd<0)
{
err_msg("socket");
return -1;
}
//绑定客户端的ip和端口
struct sockaddr_in cil;
cil.sin_family=AF_INET;
cil.sin_port=htons(cil_port);
cil.sin_addr.s_addr=inet_addr(cil_ip);
if(bind(fd,(struct sockaddr*)&cil,sizeof(cil))<0)
{
err_msg("cil's bind");
return -1;
}
printf("cil's bind success\n");
//定义服务器的地址信息结构体变量用于发送函数的发送对象
struct sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(ser_port);
sin.sin_addr.s_addr=inet_addr(ser_ip);
socklen_t size=sizeof(sin);
/**********************************开始定义读写请求服务器下载包的协议数组*******************************************/
//定义一个字符数组 用于发送数据包
char buf[516]="";
//根据下载包协议定义数组
short* p1=(short*) buf; //定义一个short类型的指针指向数组的首地址 并将他类型转换为short
*p1=htons(1); //将协议中的操作码的读权限所对应的1填入指针中******操作码********
char* p2=(char*)(p1+1); //定义一个char 类型的指针指向数组中文件名所对应的位置****文件名****
strcpy(p2,"5.png"); //将下载服务器中的文件名5.png填到里面 因为strcpy自动补\0,所以后面
//后面不用指针指向请求服务器下载下载包协议中0的位置******文件名*******
char* p3=p2+strlen(p2)+1; //strlen不计算字符串的\0位 但是请求下载下载包协议中有0位 所以加1*****模式**
strcpy(p3,"octet"); //将请求下载包协议中的模式放入数组的p3位置
//因为strcpy将字符串复制后自动补\0
//所以请求下载协议包最后一位不补\0;
/********************************读写请求服务器下载下载包的协议数组至此定义完毕**************************************/
/*****************************开始定义服务器返回客户端的数据包协议数组******************************************/
//定义一个字符数组,用于存储服务器发过来的数据包里面的协议
char arr[516]="";
/****************************返回客户端的数据包协议数组定义完毕**************************************************/
//发送请求下载包数据
if(sendto(fd,buf,size,0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
err_msg("sendto");
return -1;
}
ssize_t count=0;
//打开一个文件接受数据
umask(0);
int fp=open("./1.png",O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fp<0)
{
err_msg("open");
return -1;
}
int seclect=0;
while(1)
{
printf("***************请输入功能选项****************\n");
printf("***************1.下载************************\n");
printf("***************2.上传************************\n");
printf("***************3.退出功能菜单****************\n");
scanf("%d",&seclect);
while(getchar()!=10);
switch(seclect)
{
case 1:
while(1)
{
//接收下载包数据
if((count=recvfrom(fd,arr,sizeof(arr),0,(struct sockaddr*)&sin,&size))<0)
{
err_msg("recvfrom");
return -1;
}
//下载包中的数据存储到打开的文件中
if(write(fp,arr+4,count-4)<0)
{
err_msg("write");
return -1;
}
//判断是否为错误包,为错误包退出循环,下载包<516下载结束退出循环
if(5==arr[1])
{
printf("差错码:[%d] 差错信息:[%s]",ntohs(*(short*)(arr+2)),arr+4);
return -1;
}
if(count<516)
{
printf("下载完成,请继续选择功能\n");
break;
}
//将下载包的操作码改为回应保协议
arr[1]=4;
//发送回应包
if(sendto(fd,arr,4,0,(struct sockaddr*)&sin,sizeof(sin))<0)
{
err_msg("sendto");
return -1;
}
}
case 2:
//上传函数
upload(fd,sin);
break;
break;
case 3:
goto END;
default:
printf("请输入'1 2 3',选择功能\n");
continue;
}
}
//关闭套接字
END:
close(fd);
close(fp);
return 0;
}
效果:
下载:
上传: