//协义头 protocol.h
#ifndef PROTOCOL_H
#define PROTOCOL_H
//定义错误号
#define ERR_CHECKNUM 00000001//校验错误
#define ERR_GETFILE_NOTHING 00000002//没有要获取的文件
//定义宏指令
#define REQ_CMD_GETFILELS 000000001//获取文件列表请求
#define REV_CMD_GETFILELS 000010001//获取文件列表应答
#define REQ_CMD_GETFILE 000000002//获取文件
#define REV_CMD_GETFILE 000010002//获取文件
//定义协议头
typedef struct HEAD{
int id; //代表本次发送数据的编号
int cmd; //指令
int len; //总长
int size;//本次长度
int err; //错误号 0为正确,非零为错误
int cknum;//校验码
} head_t;
//定义发送的数据
//1. 获取文件列表请求
struct REQFILELS{
char dirname[256]; //请求列表时,可指定目录名
};
//2. 获取列表的应答
//发送的数据为 char数组类型,长度在head中指定。文件名与文件名之间用 "|"分隔
//3.获取文件请求
struct REQFILE{
char filename[256]; //请求时,必须指定要下载的包含目录的文件名
};
//4.获取文件应答
//发送文件数据,本次发送的长度,记录在head中,当累计长度>=总长,代表发送完毕
struct REVFILE{
char filename[256];
char data[2048];
};
#endif
//read.c 客户端
#include
#include
#include
#include
#include
#include "libsock/libcli.h"
#include "protocol.h"
char sendbuf[4096];
//校验码
unsigned short cal_chksum(char *addr,int len){
int nleft=len;
int sum=0;
unsigned short *w=(unsigned short*)addr;
unsigned short answer=0;
//把ICMP报头二进制数据以2字节为单位累加起来
while(nleft>1){
sum+=*w++;
nleft-=2;
}
//若ICMP报头为奇数个字节,会剩下最后一字节。把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加
if( nleft==1){
*(unsigned char *)(&answer)=*(unsigned char *)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return answer;
}
//回调,用来接收数据
int recvdata(char *buf,int size){
struct HEAD *head=(struct HEAD*)buf;
//先校验数据
/*
int cknum=head->cknum;
head->cknum=0;
if (cal_chksum(buf,sizeof(struct HEAD)+head->size)!=cknum){
//接收数据有误,装载协议头
head->cmd=head->cmd | 00010000;
head->err=ERR_CHECKNUM;
head->cknum=cal_chksum(buf,sizeof(struct HEAD));
clidev.send(buf,sizeof(struct HEAD));
return -1;
}
*/
printf("----------------------------- recv \n");
//解析协议
switch(head->cmd){
case REV_CMD_GETFILELS: //客户端的应答 要文件列表
{
char *data=buf+sizeof(struct HEAD);
char *result=strtok(data,"|");
while(result != NULL ){
printf("%s\n",result);
result=strtok(NULL,"|");
}
}
break;
case REV_CMD_GETFILE: //客户端的应答 要文件
{
static int allsize=0;
static fd=0;
char *filename=buf+sizeof(struct HEAD);
//打开文件
if (allsize==0){
printf("--------- file 1\n");
fd=open(filename,O_CREAT | O_RDWR);
}
if (fd==-1) return -1;
printf("--------- file 2\n");
//保存数据
write(fd,buf+sizeof(struct HEAD)+256,head->size-256);
allsize+=head->size-256;
//关闭文件
if(allsize>=head->len){
printf("--------- file 3\n");
close(fd);
fd=0;
allsize=0;
}
}
break;
}
}
int main(int argc,char **argv){
int i=0;
//启动服务
int err=clidev.start(argv[1],atoi(argv[2]),recvdata);
if (err==-1) return -1;
char buf[256];
while(1){
scanf("%s",buf);
if (strcmp(buf,"l")==0) {
printf("input list dir:\n");
scanf("%s",buf);
//装载协议头
struct HEAD *head=(struct HEAD*)sendbuf;
head->id=i++;
head->cmd=REQ_CMD_GETFILELS;
head->len=256;
head->size=256;
head->err=0;
head->cknum=0;
//装载数据
char *data=sendbuf+sizeof(struct HEAD);
strcpy(data,buf);//指定要获取当前目录文件列表
printf("----dir =%s\n",data);
//校验码
head->cknum=cal_chksum(sendbuf,sizeof(struct HEAD)+head->size);
//发送
clidev.send(sendbuf,sizeof(struct HEAD)+head->size);
}
else if (strcmp(buf,"f")==0){
printf("input filename:\n");
scanf("%s",buf);
//装载协议头
struct HEAD *head=(struct HEAD*)sendbuf;
head->id=i++;
head->cmd=REQ_CMD_GETFILE;
head->len=256;
head->size=256;
head->err=0;
head->cknum=0;
//装载数据
char *data=sendbuf+sizeof(struct HEAD);
strcpy(data,buf);//指定要获取当前目录文件
//校验码
head->cknum=cal_chksum(sendbuf,sizeof(struct HEAD)+head->size);
//发送
clidev.send(sendbuf,sizeof(struct HEAD)+head->size);
}
else if (strcmp(buf,"q")==0) break; //关闭窗口
}
}
//write.c 服务端
#include
#include
#include
#include "libsock/libsev.h"
#include "protocol.h"
unsigned short cal_chksum(char *addr,int len){
int nleft=len;
int sum=0;
unsigned short *w=(unsigned short*)addr;
unsigned short answer=0;
//把ICMP报头二进制数据以2字节为单位累加起来
while(nleft>1){
sum+=*w++;
nleft-=2;
}
//若ICMP报头为奇数个字节,会剩下最后一字节。把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加
if( nleft==1){
*(unsigned char *)(&answer)=*(unsigned char *)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=~sum;
return answer;
}
char *getfilels(char *path){
static char ls[4096];
struct stat st;
char pathname[256];
DIR* fp=opendir(path);
if (fp==NULL) return NULL;
struct dirent *db;
int i=0;
while((db=readdir(fp))!=NULL){
if (db->d_name[0]!='.') { //打印文件名或字符串
sprintf(pathname,"%s%s",path,db->d_name);
stat(pathname,&st); //获取文件属性
if (S_ISREG(st.st_mode)){
if (i==0) strcpy(ls,pathname);
else sprintf(ls,"%s|%s",ls,pathname);
i++;
}
}
}
closedir(fp);
if (i==0) return NULL;
else return ls;
}
//回调,用来接收数据
int recvdata(int sockfd,char *buf,int size){
struct HEAD *head=(struct HEAD*)buf;
printf("-------------1\n");
//先校验数据
/*
int cknum=head->cknum;
head->cknum=0;
if (cal_chksum(buf,sizeof(struct HEAD)+head->size)!=cknum){
//接收数据有误
//装载协议头
head->cmd=head->cmd | 00010000;
head->err=ERR_CHECKNUM;
head->cknum=cal_chksum(buf,sizeof(struct HEAD));
sevdev.send(fd,buf,sizeof(struct HEAD));
printf("-------------2\n");
return -1;
}
*/
//解析数据
switch(head->cmd){
case REQ_CMD_GETFILELS: //客户端的请求 要文件列表
{
char *dir=buf+sizeof(struct HEAD);
printf("-------------3 %s\n",dir);
//装载协议头
head->cmd=REV_CMD_GETFILELS;
head->err=0;
char *filels=buf+sizeof(struct HEAD);
strcpy(filels,getfilels(dir));
head->len=strlen(filels);
head->size=strlen(filels);
head->cknum=cal_chksum(buf,sizeof(struct HEAD)+head->size);
//发送数据
sevdev.send(sockfd,buf,sizeof(struct HEAD)+head->size);
}
break;
case REQ_CMD_GETFILE: //客户端的请求 要文件
{
char *filename=buf+sizeof(struct HEAD);
printf("---------- get file 1 %s\n",filename);
int fd1=open(filename,O_RDONLY);
if (fd1==-1){
//发送失败应答
}
else{
printf("---------- get file 2 \n");
int allsize=lseek(fd1,0,2);
lseek(fd1,0,0);
head->cmd=REV_CMD_GETFILE;
head->err=0;
head->len=allsize;
while(allsize>0){
size=allsize%2048;
if (size==0) size=2048;
size=read(fd1,buf+sizeof(struct HEAD)+256,size);
head->size=size+256;
head->cknum=cal_chksum(buf,sizeof(struct HEAD)+size+256);
allsize-=size;
printf("---------- get file 3 %d \n",size);
//发送数据
sevdev.send(sockfd,buf,sizeof(struct HEAD)+256+size);
}
printf("---------- get file 4 \n");
close(fd1);
}
}
break;
}
}
int main(int argc,char **argv){
//启动服务
int err=sevdev.start(atoi(argv[1]),recvdata);
if (err==-1) return -1;
char buf[256];
while(1){
scanf("%s",buf);
if (strcmp(buf,"q")==0) break; //关闭窗口
}
//停止服务
sevdev.stop();
}