目录
主体功能
程序使用方法
1、运行客户端编辑
2、运行服务器
3、登录
4、注册
5、程序命令解析
6、传输文件(上传--cp、下载--lcp)
具体代码
服务器
services.c(main 函数)
sqlite.c(数据库相关模块)
demo.c(服务器与客户端交互相关模块)
demo.h
sqlite.h
makefile
客户端
client.c(main函数)
demo.c(与服务器交互相关模块)
pathread.c(线程模块,实现恢复暂停下载)
sqlite.c(登录与注册--客户端)
demo.h
pthread.h
sqlite.h
makefile
主体功能
程序总体分两部分,客户端与服务器。 1、支持上传(cp)、下载(lcp)除根目录文件任意大小的文件 2、支持多客户端连接服务器下载、上传文件 3、支持文件下载、上传的暂停与恢复 4、自动检测输入的格式,超过次数程序自动退出。 5、支持切换远程服务器(lcd)、本地客户端(cd)工作目录,以及查看目录文件(lls、ls)和当前工作目录(lpwd,pwd)。
程序使用方法
1、客户端与服务器都可以直接使用make命令编译后运行 2、客户端运行时需要输入,服务器的ip地址与端口号
1、运行服务器
服务器运行后,属于待机状态,等待服务器连接后交互信息。
2、运行客户端
运行客户端需要输入,客户端的ip地址与端口号。(程序仅支持同一网段下的客户端与服务器交互)。
3、登录
客户端运行后,可以选择登录与注册。服务器在运行之初会自动创建4个VIP用户。可以使用VIP用户直接登录。
2345678 66666666
7654321 8888888
654321 888888
54321 88888
4、注册
登录注册时,输入需要按照格式输入,否则到达次数。程序自动退出。
5、程序命令解析
客户端命令:
ls:查看当期客户端,当期目录文件
cd:切换当前客户端目录
pwd:查看当前绝对路径
cp :上传文件,格式: cp 【当前文件路径】【待上传文件名】 【目的文件路径】【目的文件名】
cp ./file1 ./file1
lcp:下载文件,格式: lcp 【远程文件路径】【远程文件名】 【目的文件路径】【目的文件名】
lcp ./file1 ./file1
***除开目的文件名不能与所传路径下的文件重名外,所有的路径(除根目录)与文件名都可以根据自己意愿确定。
***程序会检测文件是否存在,是否重名,是否为空文件,并反馈信息。
lls:查看服务器当前目录文件
lpwd:产看服务器当前工作路径
lcd:切换服务器工作目录
quit:客户端退出
lcp:
服务器命令:
CTRL+c:退出服务器,并自动删除数据库。所有账户信息清零。
6、传输文件(上传--cp、下载--lcp)
文章来源:https://www.toymoban.com/news/detail-515960.html
程序具备恢复与暂停功能,在上传或下载过程中。输入‘1’表示暂停下载、上传。输入‘2’表示恢复下载、上传。文章来源地址https://www.toymoban.com/news/detail-515960.html
具体代码
服务器
services.c(main 函数)
int fid = 0;
#include"sqlite.h"
int main(int argc, char* argv[])
{
int type = 0;
int fd1,pid,ret;
int fid = init_socket();
if(fid < 0)
{
printf("init_socket failed.\n");
return -1;
}
signal(SIGCHLD,handler);//捕捉自进程信号,进行处理
signal(SIGINT,handler);//捕捉自进程信号,进行处理
sqlite3 *db;
if(init_vip(&db) == -1)//先创建两个用户
{
printf("failed\n");
close(fd1);
system("rm ./jkl.db");
exit(-1);
}
while(1)
{
fd1 = accept_client(fid);//等待客户端接入
if(fd1 == -1)
{
close(fid);
return -1;
}
pid = fork();
if(pid == -1)
{
perror("fork:");
}else if(pid == 0 )//子进程和接入客户端交互
{
ret = usr_into_system(fd1,&db);//客户端登陆、注册
if(-1 == ret )
{
close(fd1);
exit(-1);
}else if(ret == 13 )
{
printf("客户端登陆成功 \n");
}
information_from_client(&type,fd1);//循环检测客户端输入
exit(0);
}
}
close(fid);
exit(0);
return 0;
}
sqlite.c(数据库相关模块)
#include"sqlite.h"
extern int vip;
int init_vip(sqlite3 **db1)//初始化数据库,创建一张表,表中两个vip
{
char sql[100] = {0};
if(init_seqlite("./jkl.db",db1) == -1)
return -1;
strcpy(sql,"create table student(vip integer, log text, password text);");
if(init_usr(*db1,sql) == -1)
return -1;
strcpy(sql,"insert into student values(1 , '2345678', '66666666');");
if(init_usr(*db1,sql) == -1)
return -1;
strcpy(sql,"insert into student values(1 , '7654321', '8888888');");
if(init_usr(*db1,sql) == -1)
return -1;
strcpy(sql,"insert into student values(1 , '654321', '888888');");
if(init_usr(*db1,sql) == -1)
return -1;
strcpy(sql,"insert into student values(1 , '54321', '88888');");
if(init_usr(*db1,sql) == -1)
return -1;
return 0;
}
int init_seqlite(char*r,sqlite3 ** db)//创建一张表
{
if(0 != sqlite3_open(r,db) )
{
perror("open");
return -1;
}
return 0;
}
int init_usr(sqlite3* db,char* sql)//创建用户
{
if(0 != sqlite3_exec( db,sql,NULL,NULL,NULL))
{
perror("exec");
return -1;
}
return 0;
}
int usr_into_system(int fd, sqlite3 **db)//客户端登陆注册
{
sqlite3 *db1 = *db;
int a = 0;
int ret1,ret2;
struct msgdata msg;
bzero(&msg,sizeof(msg));
strcpy(msg.data,"输入 1(登陆) or 2(注册).");
send(fd,&msg,sizeof(msg),0);//提醒客户端输入
// printf("services put success: %s\n",msg.data);
while(1)
{
bzero(msg.data,sizeof(msg.data));
if( 0 == recv(fd,&msg,sizeof(msg),0))//接收客户端的输入
break;
// printf("msg.type =%d\n",msg.type);
//vip = msg.j;
int n =0 ;
char buf1[50] ={0};
char buf2[50] ={0};
strcpy(buf1,msg.data);
strcpy(buf2,strtok_str(buf1,0));
strcpy(buf1,strtok_str(msg.data,1));
// printf("buf1:%s\n",buf1);//密码
// printf("buf2:%s\n",buf2);//帐号
if(msg.type == 1)
{
msg.type = 0;
int x=0,y=0;
ret1 =select_data(db1,1,buf2,&x);
ret2 =select_data(db1,2,buf1,&y);
if( (ret1 == 1) && (ret2 == 1))
{
if( ((x != 0) &&(y != 0) ) && (x == (y) - 1) )
{
// printf("x= %d y =%d\n",x ,y);
msg.type = 1;
send(fd,&msg,sizeof(msg),0);//告诉客户端登陆成功
return 13;
}else{
msg.type = -1;
send(fd,&msg,sizeof(msg),0);
continue;
}
}else{
msg.type = -1;
send(fd,&msg,sizeof(msg),0);
continue;
}
/*
if( (select_data(db1,1,buf2) == 1) && (select_data(db1,2,buf1) == 1) )
{
msg.type = 1;
send(fd,&msg,sizeof(msg),0);//告诉客户端登陆成功
return 13;
}else{
msg.type = -1;
send(fd,&msg,sizeof(msg),0);
continue;
}
*/
}else if(msg.type == 2)
{
// printf("j = %d\n",msg.j);
if(msg.j == 1)
{
vip = 1;
}else if(msg.j == -1)
{
vip = 0;
}
if(add_usr_to_system(db1,buf2,buf1,&msg) == -1)
{
msg.type = -1;
send(fd,&msg,sizeof(msg),0);
continue;
}else{
msg.type = 1;
send(fd,&msg,sizeof(msg),0);
continue;
}
}else if(msg.type ==-1)
{
printf("client quit.\n");
return -1;
}
}
return 0;
}
int select_data(sqlite3* db, int m,char* buf,int* x)
{
int ret =0 ;
char sql[50] = {0};
char **result;
int R, C;
if(0 != sqlite3_get_table(db, "select *from student;", &result, &R, &C, NULL))
{
printf("select is default\n");
return -1;
}
int i, j;
m = C +m;
for(i = 0; i <R;i++ )
{
// printf("%s \n",result[m]);
// printf("%d buf = %d\n",strlen(result[m]),strlen(buf));
ret = strcmp(result[m],buf) ;
// printf("%d\n",ret);
if((ret == 0) && (strlen(buf) == strlen(result[m])))//找到相同 数据
{
// printf("this m result %s %d\n",result[m],strlen(result[m]));
// printf("this m buf %s %d\n",buf,strlen(buf));
*x = m;
return 1;
}
m +=3;
}
return 0;//没有找到相同数据
}
int add_usr_to_system(sqlite3*db,char *buf2,char *buf1,struct msgdata* msg)//注册
{
int x;
char sql[100] ={0};
// printf("buf2 = %s\n",buf2);
int ret = select_data(db,1,buf2,&x) ;
if(ret == 1 )
{
strcpy(msg->data,"用户或已存在.");
return -1;
}else if(ret == -1)
{
return -1;
}
sprintf(sql,"insert into student values(%d , '%s', '%s');",msg->j,buf2,buf1);
if(init_usr(db,sql) == -1)
return -1;
return 0;
}
demo.c(服务器与客户端交互相关模块)
#include"demo.h"
#include<pthread.h>
//extern int type;
int vip =1;
int pthread_type = 2;
int type_pth = 2;
void * input(void*);
extern int fid;
int init_socket()//初始化套接字
{
int fd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == fd)
{
perror("socket:");
return -1;
}else{
printf("socket success.\n");
}
int on =1;
if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on))< 0)//设置端口可以复用
{
perror("setsockopt:");
return -1;
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(6150);
addr.sin_addr.s_addr = inet_addr("0.0.0.0");
if(bind(fd,(struct sockaddr*)&addr,sizeof(addr)) < 0 )
{
perror("bind:");
return -1;
}else{
printf("bind success.\n");
}
if(listen(fd,13) < 0)
{
perror("listen:");
return -1;
}else{
printf("listen........\n");
}
return fd;
}
int accept_client(int fd)//接收客户端连接
{
struct sockaddr_in addr;
socklen_t len;
int acce_fd = accept(fd,(struct sockaddr*)&addr,&len);
if(acce_fd == -1)
{
perror("accept:");
return -1;
}else{
printf("accept success.\n");
printf("\033[1;31mip:%s,port:%d\033[0m\n",inet_ntoa(addr.sin_addr),ntohs(addr.sin_port));
}
return acce_fd;
}
void handler(int no)//信号处理函数
{
int pid;
if(no == SIGCHLD)
{
pid = waitpid(-1,NULL,WNOHANG);//非阻塞等待子进程推出
if(-1 == pid)
{
perror("waitpid :");
}else{
//printf("\033[1;34msignal: child quit,pid:%d\033[0m\n",pid);
}
}else if(no == SIGINT)
{
system("rm ./jkl.db");
close(fid);
printf("services quit\n");
exit(0);
}
}
int information_from_client(int* type,int fd1)//循环接收客户端信息
{
int ret,open_fd;
struct msgdata *msg = (struct msgdata*)malloc(sizeof(struct msgdata));
while(1)
{
bzero(msg,sizeof(struct msgdata));
ret = recv(fd1,msg,sizeof(struct msgdata),0);
if(ret == -1)
{
perror("recvmsg:");
break;
}else if (ret == 0)
{
break;
}else{
printf(" \033[1;34m information from clent:%s\033[0m\n",msg->filename);
if(get_command(type,msg,fd1) == 13 )
break;
}
}
free(msg);
msg = NULL;
close(fd1);
return 0;
}
int get_command(int* type,struct msgdata* msg,int fd)//分析命令
{ char buf[50] = {0};
strcpy(buf,msg->filename);
// printf("get buf =%s\n",buf);
if(strncmp(buf,"lcd",3) == 0) *type = 1;
else if(strncmp(buf,"lls",3) == 0) *type = 2;
else if(strncmp(buf,"lpwd",4) == 0) *type = 3;
else if(strncmp(buf,"lcp",3) == 0) *type = 4;
else if(strncmp(buf,"cp",2) == 0) *type = 5;
else if(strncmp(buf,"quit",4) == 0) *type = 6;
else{
printf("input error|n");
return -1;
}
// printf("type =%d\n",*type);
if(deal_command(type,msg,fd) == 13)
return 13;
return 0;
}
int deal_command(int *type,struct msgdata* msg,int fd)//处理命令
{
char *p =NULL;
char *p1 = NULL;
switch(*type)
{
case 1:
p1 = msg->filename;
p1 = p1+3;
if(*p1 == '\0')
{
if( chdir("/")== -1)
{
msg->type == -1;
strcpy(msg->data,strerror(errno));
}else{
strcpy(msg->data,"\033[0;34m lcd:success\033[0m");
}
send(fd,msg,sizeof(struct msgdata),0);//反馈错误信息
}else{
p = strtok_str(msg->filename,1);
if(chdir(p) == -1)
{
msg->type == -1;
strcpy(msg->data,strerror(errno));
}else{
strcpy(msg->data,"\033[0;34m lcd:success\033[0m");
//strcpy(msg->data,"success\n");
}
send(fd,msg,sizeof(struct msgdata),0);//反馈错误信息
}
break;
case 2:
char buf[123] = {0};
p1 = msg->filename +3;
if(*p1 == ' ') //判断命令lls 后跟了选项
{
p = strtok_str(msg->filename,1);
sprintf(buf,"ls %s",p); //拼凑ls 加选项
msg->type =3;
// printf("this is lls -xxxx \n");
send(fd,msg,sizeof(struct msgdata),0);// 告诉客户端需要打印
send_to_client(buf,fd);//读取并发送ls 结果
}else if (*p1 == '\0')
{
//iprintf("this is 2\n");
msg->type =3;
//printf("this is lls \n");
send(fd,msg,sizeof(struct msgdata),0);//告诉客户端可以后面的打印
send_to_client("ls",fd);
}else{
//printf("this is 3\n");
msg->type = -1;
strcpy(msg->data,"lls: input error");
send(fd,msg,sizeof(struct msgdata),0);//告诉客户端命令格式错误
}
break;
case 3:
char *p = msg->filename;
p = p+4;
if(*p == '\0')
{
send_to_client("pwd",fd);
}else{
msg->type = -1;
strcpy(msg->data,"lpwd:input error");
send(fd,msg,sizeof(struct msgdata),0);
}
break;
case 4:
p = strtok_str(msg->filename,1);
send_file_to_client(p,fd);//发送文件
break;
case 5://实现cp功能,接收文件
accept_file(msg,fd);//接收文件
break;
case 6:
printf("clenit quit\n");
return 13;
break;
}
// printf("this is end end\n");
return 0;
}
char *strtok_str(char* str,int i)//分割字符串
{
char *p = strtok(str," ");
while(i--)
{
p = strtok(NULL," ");
}
// printf("%s\n",p);
return p;
}
int send_to_client(char* str,int fd)//发送命令后的内容到客户端,lpwd lls
{
int ret ,ret1;
// printf("str=%s\n",str);
struct msgdata msg;
bzero(&msg,sizeof(msg));
FILE* fd1 = popen(str,"r");
if(fd1 == NULL)
{
perror("popen");
}
while(1)
{
ret = fread(msg.data,sizeof(msg.data),1,fd1);
if(ret == -1)
{
perror("fread");
pclose (fd1);
return -1;
}else if(ret == 0)//读取到末尾了
{
// printf("str= %s\n",str);
if(NULL != strstr(str,"pwd") )
{
msg.type = 2; // 告诉客户端是pwd,并且读到末尾了
}else{
msg.type = 13; //lls,并且读到末尾了
}
ret = send(fd,&msg,sizeof(msg),0);
if(ret == -1)
{
perror("send");
}
// printf("msg type %d\n",msg.type);
bzero(msg.data,sizeof(msg.data));
break;
}else{
ret = send(fd,&msg,sizeof(msg),0);
if(ret == -1)
{
perror("send");
}
bzero(msg.data,sizeof(msg.data));
}
}
pclose(fd1);
return 0;
}
int accept_file(struct msgdata* Msg,int fd)//接收客户端复制到的文件,cp
{
char *str = strtok_str(Msg->filename,2);//获取文件名
int ret,i=0,j,op_fd;
int tail;
char buf[130] = {0};
memset(buf,'-',100);
int k = 0;
struct msgdata msg;
int size = sizeof(msg.data);
bzero(&msg,sizeof(msg));
recv(fd,&msg,sizeof(msg),0);//确认客户端,文件是否打开成功
if(msg.type == -1)//打开失败,终止本次传输
{
printf("\033[传输失败\033[0m\n\n");
return -1;
}else{//打开成功,接收本次传输的信息,次数
j = msg.j;
tail = msg.file_len - (j-1)*(size);//最后一次的长度
// printf("%s\n",msg.data);
}
struct msgdata msg2;
op_fd = open(str,O_CREAT|O_EXCL|O_RDWR,0666);//创建文件
if(op_fd == -1)
{
perror("open");
printf("\033[0;31m创建文件失败\033[0m\n");
msg2.type =-1;
send(fd,&msg2,sizeof(msg2),0);//告诉客户端,这边创建失败。不要发送。终止传输
return -1;
}
msg2.type =1;
send(fd,&msg2,sizeof(msg2),0);//告诉客户端,这边创建成功。可以发送,开始接收数据
int s = 0;
if(vip == 1)
{
s =1;
}else{
s =6;
}
// printf("vip =%d , s =%d \n",vip,s);
while(1)
{
i++;
// bzero(msg.data,sizeof(msg.data));
memset(msg.data,0,sizeof(msg.data));
ret = recv(fd,&msg,sizeof(msg),0);
if(ret == -1)
{
perror("read");
break;
}
int ret = write(op_fd,msg.data, ((i<j)?size:tail) );
if(ret == -1)
{
perror("write:");
}
float g = (((float)i/j)*100 );
while(k < (int)g)
{
buf[k++] ='*';
printf("\033[0;32m<%s>\033[0;31m[%4.2f%%]\033[0m\033[0m \r",buf,g);
fflush(stdout);
usleep(70000*s);
}
if( j == i)
{
break;
}
}
printf("\n传输完毕.\n");
return 0;
}
int send_file_to_client(char *p ,int fd)//lcp,由服务器发送文件
{
int ret ,i = 0,j,s=0;
struct msgdata msg,msg1;
float g;
int size = sizeof(msg.data);
char buf1[50] = {0};
char buf[130] = {0};//精度条
memset(buf,'-',100);
int k =0 ;
int op_fd = open(p,O_RDONLY);// 打开本地文件
if(op_fd == -1)//打开失败
{
msg.type = -1;//告诉客户端本地文件不存在,无法传输文件
perror("open");
strcpy(msg.data,"\033[0;31m远程文件不存在,无法完成传输\033[0m\n");
send(fd,&msg,sizeof(msg),0);//告诉客户端文件打开失败
return -1;
}else{//打开成功
msg.file_len = lseek(op_fd,0,SEEK_END);//获取文件大小
lseek(op_fd,0,SEEK_SET);
if(msg.file_len == 0)
{
msg.type = -1;
strcpy(msg.data,"\033[0;31m下载文件为空,不支持传输\033[0m\n");
send(fd,&msg,sizeof(msg),0);//告诉客户端,传输终止
return -1;
}
msg.type =1;
msg.j = msg.file_len/size + (((msg.file_len%size) > 0)?1:0);//获取本次传输次数
strcpy(msg.data,"\033[0;34m service: 远程文件存在,可以传输\033[0m\n");
send(fd,&msg,sizeof(msg),0);//告诉客户端,发送的次数\文件大小
j = msg.j;
}
//send(fd,&msg,sizeof(msg),0);
//等待客户端创建新文件是否成功
struct msgdata msg2;
recv(fd,&msg2,sizeof(msg2),0);
if(msg2.type == -1)//客户端创建文件失败,无法完成传输
{
printf("\033[0;31m客户端创建文件失败,或文件已经存在,无法完成本次传输.\033[0m\n");
close(op_fd);
return -1;
}else{
if(vip == 1)
{
s =1;
}else{
s =6;
}
pthread_t tid;
while(1){
if(i == 0)
{
pthread_create(&tid,NULL,input,(void *)&fd);
}
if(type_pth == 2)
{
i++;
bzero(msg.data,sizeof(msg.data));
ret = read(op_fd,msg.data,sizeof(msg.data));//读取文件
if(ret == -1)
{
perror("read");
close(op_fd);
return -1;
}
send(fd,&msg,sizeof(msg),0);//文件数据发给客户端
g = (((float)i/j)*100 );
while(k < (int)g)
{
buf[k++] ='*';
printf("\033[0;32m<%s>\033[0;31m[%4.2f%%]\033[0m\033[0m \r",buf,g);//打印进度条
fflush(stdout);
usleep(70000*s);
}
if(j == i)
{
pthread_cancel(tid);
pthread_join(tid,NULL);
break;
}
}
}
printf("\n文件传输完毕.\n");
}
}
void * input(void* fd)
{
// printf("fd === %d\n",*((int*)fd));
struct msgdata msg;
while(1)
{
if(recv(*((int*)fd),&msg,sizeof(struct msgdata),0) == -1)
perror("recv");
if(msg.type_pth == 1)
{
type_pth = 1;
}else if(msg.type_pth == 2 )
{
type_pth = 2;
}
// printf("type =%d ms =%d\n",type_pth,msg.type_pth);
}
}
demo.h
#include<sys/types.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<errno.h>
#define lcd 1
#define lls 2
#define lpwd 3
#define lcp 4
#define cp 5
#define quit 6
#define my_exit 7
struct msgdata{
char filename[50];
char data[300];
int type;
int file_len;
int j;
int type_pth;
};
int accept_client(int fd);//接收客户端连接
int init_socket();//初始化套接字
void handler(int no);//信号处理函数
int information_from_client(int* type,int fd1);//接收客户端首次发出的信息
int get_command(int* tyep ,struct msgdata*, int fd);//分析命令
int deal_command(int* type,struct msgdata*,int fd );//处理命令
char *strtok_str(char *,int);//分割字符串
int accept_file(struct msgdata *,int fd);//接收文件,cp时,服务器接收文件
int send_to_client(char* str,int fd);//lls lpwd后的信息 发送到客户端
int send_file_to_client(char *p ,int fd);//发送文件到客户端
sqlite.h
#include<stdio.h>
#include<sqlite3.h>
#include<string.h>
#include"demo.h"
int init_seqlite(char*,sqlite3 ** db);//创建一个数据
int init_usr( sqlite3* db,char *);//创建用户
int init_vip(sqlite3 **);//创建两个vip
int usr_into_system();//客户端登陆
int select_data(sqlite3*,int,char*,int*);//查找数据,在数据库中
int add_usr_to_system(sqlite3*,char* ,char*,struct msgdata*);//注册帐号
makefile
test:services.o demo.o sqlite.o
gcc -Wall services.o demo.o sqlite.o -o test -lsqlite3 -L/usr/local/lib -I/usr/local/include -lpthread
services.o:services.c
gcc -c services.c -o services.o
demo.o:demo.c
gcc -c demo.c -o demo.o
sqlite.o:sqlite.c
gcc -c sqlite.c -o sqlite.o -lsqlite3
.PHONY:clean
clean:
rm -r ./*.o test
# -lsqlite3 -L/usr/local/lib -I/usr/local/include -static -lpthread
客户端
client.c(main函数)
#include"sqlite.h"
int fd;
int main(int argc, char *argv[])
{
int ret;
char buf[50] = {0};
int type = 0;
fd = connect_services(argc,argv[1],argv[2]);
if(fd == -1)
{
printf("connect_services failed\n");
return -1;
}
ret = login_reges_to_servises(fd);
if(ret == -1)
{
close(fd);
return -1;
}else if(ret == 13)
{
printf("本程序支持功能:\n1、下载文件:cp [路径][文件名] [目标路径][目标文件名]\n2、上传文件:lcp [路径][文件名] [目标路径][目标文件名]\n3、查看本地文件、切换本地工作目录、查看工作目录路径(ls ,cd,pwd及相关选项)\n4、查看远程文件、切换目录、路径(lls、lcd、lpwd)及相关选项\n");
}
get_command(buf,sizeof(buf),&type);//对命令进行解析
close(fd);
return 0;
}
demo.c(与服务器交互相关模块)
#include"demo.h"
#include"pthread.h"
int vip = 1;
int pthread_type = 2;
int pthread_interrupt( pthread_t*);//建立线程 cp(上传文件)
int pthread_interrupt2( pthread_t*);//建立线程 ,lcp(下载文件)
extern int fd;
int connect_services(int argc,char* ip, char * port)//连接
{
if(argc < 3){
printf("too few arguements: ./test [ip] [port]\n" );
return -1;
}
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
perror("socket");
return -1;
}
printf("sockfd: %d\n", sockfd);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_port = htons( atoi(port) ),
.sin_addr.s_addr = inet_addr( ip )
};
if( connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("connect");
close(sockfd);
return -1;
}
return sockfd;
}
int get_command(char *str,int size,int* type )//分析命令
{
char *p = NULL;
while(1)
{ memset(str,0,50);
fgets(str,size,stdin);
p = str+ strlen(str)-1;
*p = '\0';
// printf("str strlen= %d\n",strlen(str));
if(strncmp(str,"cd",2) == 0) *type =1;
else if(strncmp(str,"lcd",3) == 0) *type =2;
else if(strncmp(str,"ls",2) == 0) *type =3;
else if(strncmp(str,"lls",3) == 0) *type =4;
else if(strncmp(str,"pwd",3) == 0) *type =5;
else if(strncmp(str,"lpwd",4) == 0) *type =6;
else if(strncmp(str,"cp",2) == 0) *type =7;
else if(strncmp(str,"lcp",3) == 0) *type =8;
else if(strncmp(str,"quit",4) == 0) *type =9;
else {
printf("input error:\n");
continue;
}
// printf("type %d\n",*type);
if( 13 == deal_comman(*type,str))
return -1;
}
return 0;
}
char * strtok_str(char* str,int i)//分割字符串
{
char *p = strtok(str," ");
while(i--)
{
p = strtok(NULL," ");
}
return p;
}
int deal_comman(int type,char *str)//处理命令
{
struct msgdata msg;
bzero(&msg,sizeof(msg));
int ret;
char *p =NULL;
char buf[30] ={0};
switch(type)
{
case 3:
case 5:
system(str);
printf("\033[0;34m===========================================================\033[0m\n\n");
break;
case 1:
p = strtok_str(str,1);
chdir(p);
printf("\033[0;34m===========================================================\033[0m\n\n");
break;
case 2:
strncpy(msg.filename,str,strlen(str));
ret = send_command_to_service(msg);
recv(fd,&msg,sizeof(msg),0);
if(msg.type == -1)
{
printf("\033[0;31m%s\033[0m\n",msg.data);
printf("type =%d\n",msg.type);
}
printf("%s\n",msg.data);
printf("\033[0;34m===========================================================\033[0m\n\n");
break;
case 4:
case 6:
strncpy(msg.filename,str,strlen(str));
send_command_to_service(msg);//发送lpwd lls命令
if(ret == -1)
{
printf("error:send_to_services.\n");
}
recv(fd,&msg,sizeof(struct msgdata),0);//接收反馈信息,判断是否打印
// printf("msg type = %d\n",msg.type);
if(msg.type == 2)//反馈为lpwd
{
printf("%s",msg.data);
// break;
}
else if(msg.type == -1)//反馈为命令格式错误
{
printf("\033[0;31m%s\033[0m\n",msg.data);
printf("\033[0;34m===========================================================\033[0m\n\n");
break;
}else{
while(1)
{
if(msg.type == 13)
{
break;
}
ret = recv(fd,&msg,sizeof(msg),0);
if(ret == -1)
{
perror("recv");
break;
}else if(ret == 0)
{
printf("services quit:\n");
break;
}else{
printf("%s",msg.data);
}
bzero(msg.data,sizeof(msg.data));
}
}
printf("\033[0;34m===========================================================\033[0m\n\n");
break;
case 7://实现cp功能,向服务器发文件
bzero(&msg,sizeof(msg));
strncpy(msg.filename,str,strlen(str));
send_command_to_service(msg);//文件名及路径传给服务器
p = strtok_str(str,1);//获取本地文件名及路径
send_file_to_services(p);//打开本地文件并传输文件
break;
case 8:
strncpy(msg.filename,str,strlen(str));
send_command_to_service(msg);//命令发送到,服务器
p = strtok_str(str,2);
recv_file_from_services(p);
break;
case 9:
printf("client quit\n");
strncpy(msg.filename,str,strlen(str));
send_command_to_service(msg);//命令发送到,服务器
return 13;
break;
default:
printf("\033[1;31miuput error:\033[0m\n");
}
return 0;
}
int send_command_to_service(struct msgdata msg)//部分解析后的命令发送到服务器:lls lpwd lcd quit
{
int ret = send(fd,&msg,sizeof(msg),0);
if(-1 == ret)
{
perror("send");
exit(-1);
}
return 0;
}
int send_file_to_services(char *filename)//发送文件到服务器,cp
{
int ret ,i = 0,j,s=0;
struct msgdata msg;
float g;
int size = sizeof(msg.data);
char buf[130] = {0};//精度条
memset(buf,'-',100);
int k =0 ;
char buf1[50] = {0};
int op_fd = open(filename,O_RDONLY);// 打开本地文件
if(op_fd == -1)//打开失败
{
msg.type = -1;//告诉服务器本地文件不存在,无法传输文件
//perror("open");
printf("\033[1;31m本地文件不存在,无法完成传输\033[0m\n");
send(fd,&msg,sizeof(msg),0);//告诉服务器文件打开失败
return -1;
}else{//打开成功
msg.file_len = lseek(op_fd,0,SEEK_END);//获取文件大小
lseek(op_fd,0,SEEK_SET);
if(msg.file_len == 0)
{
msg.type = -1;
printf("\033[1;31m上传文件为空,不支持传输\033[0m\n");
send(fd,&msg,sizeof(msg),0);//告诉服务器,传输终止
return -1;
}
msg.type =1;
msg.j = msg.file_len/size + (((msg.file_len%size) > 0)?1:0);//获取本次传输次数
send(fd,&msg,sizeof(msg),0);//告诉服务器,发送的次数\文件大小
j = msg.j;
}
//等待服务器创建新文件是否成功
struct msgdata msg2;
recv(fd,&msg2,sizeof(msg2),0);
if(msg2.type == -1)//服务器创建文件失败,无法完成传输
{
printf("\033[1;31m服务器创建文件失败,或文件已经存在,无法完成本次传输.\033[0m\n");
close(op_fd);
return -1;
}
if(vip == 1)//判断是否为vip,进而决定传输速率
{
s =1;
printf("\033[1;32m亲爱滴VIP用户,正在为你加速\033[0m\n");
}else{
s =6;
}
// printf("vip =%d , s =%d \n",vip,s);
while(1)
{
i++;
memset(msg.data,0,sizeof(msg.data));
ret = read(op_fd,msg.data,sizeof(msg.data));
if(ret == -1)
{
perror("read");
close(op_fd);
return -1;
}
send(fd,&msg,sizeof(msg),0);
g = (((float)i/j)*100 );
while(k < (int)g)
{
buf[k++] ='*';
printf("\033[0;32m [输入1(暂停)或2(恢复)]: <<%s>>\033[0;31m[%4.2f%%]\033[0m\033[0m \r",buf,g);
fflush(stdout);
usleep(70000*s);
}
pthread_t tid;
if((i == 1) && (j >1))//当传输次数大于1时,第一次传输结束就开线程
{
pthread_interrupt(&tid);
}
if(pthread_type == 1)
{
while(1)
{
bzero(buf1,sizeof(buf1));
if(pthread_type == 1)
{
// fflush(stdin);
fgets(buf1,sizeof(buf1),stdin);
if((strlen(buf1) != 2 ) || ( buf1[0] != '2') )
{
printf("\033[1;31m格式错误 \033[0m\n");
}else{
pthread_type =2;
break;
}
}
}
}
if(j == i)
{
pthread_type = -1;//传输结束,全局变量赋值为-1,线程退出
pthread_cancel(tid);
pthread_join(tid,NULL);
break;
}
}
printf("\n\033[1;36m文件传输完毕.\033[0m\n");
printf("\033[0;34m===========================================================\033[0m\n\n");
}
int recv_file_from_services(char* str)//接收文件,lcp
{
int ret,i=0,j,op_fd,s=0;
int tail;
char buf[130] = {0};
memset(buf,'-',100);
int k = 0;
struct msgdata msg;
int size = sizeof(msg.data);
bzero(&msg,sizeof(msg));
recv(fd,&msg,sizeof(msg),0);//确认服务器,文件是否打开成功
if(msg.type == -1)//打开失败,终止本次传输
{
printf("\033[%s\033[0m\n\n",msg.data);
return -1;
}else{//打开成功,接收本次传输的信息,次数
j = msg.j;
tail = msg.file_len - (j-1)*(size);//最后一次的长度
printf("%s\n",msg.data);
}
struct msgdata msg2;
op_fd = open(str,O_CREAT|O_EXCL|O_RDWR,0666);//创建文件
if(op_fd == -1)
{
perror("open");
printf("\033[0;31m创建文件失败,本地文件或已经存在\033[0m\n");
msg2.type =-1;
send(fd,&msg2,sizeof(msg2),0);//告诉服务器,这边创建失败。不要发送。终止传输
return -1;
}else{
msg2.type =1;
send(fd,&msg2,sizeof(msg2),0);//告诉服务器,这边创建成功。可以发送,开始接收数据
}
if(vip == 1)
{
s =1;
printf("\033[1;32m亲爱滴VIP用户,正在为你加速\033[0m\n");
}else{
s =6;
}
pthread_t tid2;
while(1)
{
if(i == 0)
{
pthread_interrupt2( &tid2 );//建立线程 ,lcp(下载文件)
}
i++;
bzero(msg.data,sizeof(msg.data));
ret = recv(fd,&msg,sizeof(msg),0);//接收服务器文件数据
if(ret == -1)
{
perror("read");
break;
}
int ret = write(op_fd,msg.data, ((i<j)?size:tail) );//写入本地文件
if(ret == -1)
{
perror("write:");
}
float g = (((float)i/j)*100 );
while(k < (int)g)
{
buf[k++] ='*';
printf("\033[0;32m[输入1(暂停)或2(恢复)]: <<%s>>\033[0;31m[%4.2f%%]\033[0m\033[0m \r",buf,g);//打印进度条
fflush(stdout);
usleep(70000*s);
}
if(i == j)
{
pthread_cancel(tid2);//数据传输完成,结束发送线程
pthread_join(tid2,NULL);
break;
}
}
printf("\n\033[1;36m文件传输完毕.\033[0m\n");
printf("\033[0;34m===========================================================\033[0m\n\n");
return 0;
}
pathread.c(线程模块,实现恢复暂停下载)
#include"pthrea.h"
#include"demo.h"
extern int pthread_type ;
extern int fd;
int pthread_interrupt(pthread_t * tid)
{
if(pthread_create(tid,NULL,input,NULL) != 0)
perror("pthread_create");
return 0;
}
void * input()
{
while(1)
{
if( pthread_type == -1 )
{
pthread_exit(NULL);
break;
}else
{
if( pthread_type == 2 )
{
char buf[50] = {0};
fgets(buf,sizeof(buf),stdin);
// printf("%s\n",buf);
if((strlen(buf) != 2) || (buf[0] != '1') )
{
printf("\033[1;31m格式错误\033[0m\n");
}else{
if(buf[0] == '1')
{
pthread_type = 1;
}
}
}
}
}
}
int pthread_interrupt2(pthread_t * tid)
{
if(pthread_create(tid,NULL,input2,NULL) != 0)
printf("pthread_create error\n");
return 0;
}
void * input2( )
{
char buf[50] = {0};
struct msgdata msg;
while(1)
{
fgets(buf,sizeof(buf),stdin);
if((strlen(buf) != 2) || ((buf[0] != '1') && (buf[0] != '2') ))
{
printf("\033[1;31m格式错误\033[0m\n");
}else{
if(buf[0] == '1')
{
msg.type_pth = 1;
}else if(buf[0] == '2')
{
msg.type_pth = 2;
}
int ret =send(fd,&msg,sizeof(msg),0);//告诉服务器暂停\恢复发送数据
if(ret == -1)
perror("send");
// printf("msgtype =%d ret = %d fd = %d\n",msg.type_pth,ret,fd);
}
}
}
sqlite.c(登录与注册--客户端)
#include"sqlite.h"
extern int vip;
int login_reges_to_servises(int fd)
{
char a =0;
int m = 9;
struct msgdata msg,msg1;
bzero(&msg1,sizeof(msg1));
// bzero(&msg,sizeof(msg));
recv(fd,&msg1,sizeof(msg1),0);
while(1)
{
if(m == 0)
return -1;
char str[20] ={0};
printf("\033[1;34mservices:%s\033[0m\n",msg1.data);
fgets(str,sizeof(str),stdin);
// printf("%s\n",str);
if(strlen(str) != 2 || (str[0] != '1' && str[0] != '2'))
{
printf("\033[0;31m格式错误,请输入整数‘1’(登陆)或‘2’(注册).你还有%d次机会. \033[0m\n",--m);
printf("\033[0;34m===========================================================\033[0m\n\n");
continue;
}else{
a = str[0];
}
if(a == '1')
{
bzero(&msg,sizeof(msg));
if(get_log(&msg,&m) == -1)
{
msg.type = -1;
send(fd,&msg,sizeof(msg),0);
return -1;
}else{
msg.type =1;
// printf("msg:%s\n",msg.data);
send(fd,&msg,sizeof(msg),0);//发送信息
// bzero(&msg,sizeof(msg));
recv(fd,&msg,sizeof(msg),0);
// printf("msg.type = %d\n",msg.type);
if(msg.type == -1)
{
printf("\033[0;31m密码或帐号错误,你还有%d次机会\033[0m\n",--m);
printf("\033[0;34m===========================================================\033[0m\n\n");
if(m == 0)
return -1;
continue;
}else{
if(vip == 1 )
{
printf("\033[1;34m登陆成功,亲爱的VIP。\033[0m\n");
printf("\033[0;34m===========================================================\033[0m\n\n");
}else{
printf("\033[1;34m登陆成功,你是普通用户,下载、上传速度不是很妙.\033[0m\n");
printf("\033[0;34m===========================================================\033[0m\n\n");
}
return 13;
}
}
}else if(a == '2')
{
bzero(&msg,sizeof(msg));
/*
if(get_log(&msg,&m) == -1)
{ msg.type = -1;
send(fd,&msg,sizeof(msg),0);
return -1;
}*/
puts("\033[1;34m是否需要会员,y/n\033[0m");
memset(str,0,sizeof(str));
fgets(str,sizeof(str),stdin);
if((strlen(str)) != 2 || (str[0] != 'y' && str[0] != 'n'))
{
printf("\033[0;31m格式错误,请输入整数‘y'或‘n’,你还有%d次机会.\033[0m\n",--m);
printf("\033[0;34m===========================================================\033[0m\n\n");
continue;
}
if(str[0] == 'y')
{
vip = 1;
msg.j =1;
}else{
vip = 0;
msg.j = -1;
}
if(get_log(&msg,&m) == -1)
{ msg.type = -1;
send(fd,&msg,sizeof(msg),0);
return -1;
}else{
msg.type =2;
}
send(fd,&msg,sizeof(msg),0);//发送信息
recv(fd,&msg,sizeof(msg),0);
if(msg.type == 1)
{
vip *= 1;
printf("\033[1;34m注册成功\033[0m\n");
printf("\033[0;34m===========================================================\033[0m\n\n");
// printf("%d\n",vip);
continue;
}else{
vip *= 0;
printf("\033[1;31m%s\033[0m\n",msg.data);
printf("\033[1;31m注册失败,还有%d次机会\033[0m\n",--m);
printf("\033[0;34m===========================================================\033[0m\n\n");
// printf("%d\n",vip);
continue;
}
}else{
printf("\033[0;31m格式错误\033[0m\n");
printf("\033[0;34m===========================================================\033[0m\n\n");
continue;
}
}
return 0;
}
int get_log(struct msgdata *msg,int *n)
{
char buf1[50] = {0};
char buf2[50] = {0};
char *p =NULL;
while(1)
{
if(*n == 0)
return -1;
fflush(stdin);
puts("\033[1;34m输入帐号(不超过8位的字符,不能包含空格)\033[0m");
fgets(buf1,sizeof(buf1),stdin);
p = buf1 + strlen(buf1);
*(--p) = '\0';
puts("\033[1;34m输入密码(不超过8位的字符,不能包含空格)\033[0m");
fgets(buf2,sizeof(buf2),stdin);
p = buf2 + strlen(buf2);
*(--p) = '\0';
if(strlen(buf1) >8 || strstr(buf1," ") != NULL || strlen(buf2) >8 || strstr(buf2," ") != NULL )
{
*n -=1;
printf("\033[0;31m格式错误,重新输入,你还有%d次机会\033[0m\n",*n);
printf("\033[0;34m===========================================================\033[0m\n\n");
continue;
}else{
printf("\033[1;34m格式正确\033[0m\n");
sprintf(msg->data,"%s %s",buf1,buf2);
// printf("%s\n",msg->data);
return 0;
}
// printf("n =%d\n",n);
}
return 0;
}
demo.h
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define cd 1
#define lcd 2
#define ls 3
#define lls 4
#define pwd 5
#define lpwd 6
#define cp 7
#define lcp 8
#define quit 9
struct msgdata{
char filename[50];
char data[300];
int type;
int file_len;
int j;
int type_pth;
};
char * strtok_str(char*,int i);//分割字符串
int connect_services(int argc,char* ip, char * port);//链接服务器
int get_command(char *str,int size,int *type);//解析命令
int deal_comman(int type,char* str);//处理命令
int send_command_to_service(struct msgdata msg);//lls lpwd 部分解析后命令发送服务器
int send_file_to_services(char *filename);//发送文件到服务器
int recv_file_from_services(char* str);//接收文件
pthread.h
#include<pthread.h>
#include<unistd.h>
#include<string.h>
#include<stdio.h>
int pthread_interrupt( pthread_t*);//建立线程, cp(上传文件)
int pthread_interrupt2( pthread_t*);//建立线程 ,lcp(下载文件)
void * input();
void * input2();
sqlite.h
#include"demo.h"
#include<stdio.h>
#include<sqlite3.h>
#include<string.h>
sqlite3** init_seqlite(char *r,sqlite3 ** db);//创建一个数据
int init_usr(char* r , sqlite3* db);//创建用户
int login_reges_to_servises(int );// 客户端进入登陆注册
int client_log_to_system(int fd);
int get_log(struct msgdata* ,int*);
makefile
test:client.o demo.o pthrea.o sqlite.o
gcc -Wall client.o demo.o pthrea.o sqlite.o -o test -lsqlite3 -L/usr/local/lib -I/usr/local/include -lpthread
client.o:client.c
gcc -c client.c -o client.o
demo.o:demo.c
gcc -c demo.c -o demo.o
pthread.o:pthread.c
gcc -c pthread.c -o pthread.o
sqlite.o:sqlite.c
gcc -c sqlite.c -o sqlite.o
.PHONY:clean
clean:
rm -r ./*.o test
到了这里,关于个人项目----基于TCP的文件传输系统的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!