1.查看:通过客户端查看服务器端都有哪些文件?
(删除,重命名)
2.下载 :(显示下载百分比)断点续传
3.上传
客户端发送命令信号,服务器进行执行,并回复客户端。
将命令的名字作为协议。
先创建管道(用于父子进程间通信,传递数据(ls后显示的结果)),再fork产生子进程,在子进程中,用管道的写端覆盖标准输出(将管道的写端使用dup覆盖标准输出 )(标准输出的数据,客户端得不到)
, 在把子进程替换成要执行的命令,当客户端发送这个命令,管道就会写入数据,ji紧接着父进程,从管道中读取数据,发送给客户端。(多个子进程就可以执行多个命令)
举个栗子:因为比如,客户端发送的命令是ls -l,我要使用系统已经有的ls,但是系统的ls,会直接标准输出(标准输出的数据,客户端得不到),所以需要使用管道的写端把标准输出覆盖掉,(管道的写端在子进程中),就相当于把ls的获取的数据写入管道中,让父进程来读取就可以了,(需要建立socket连接)再发给客户端,从而也就用客户端发来的命令,获取要查看的数据。
rm删除数据后,是没有数据写入管道中的,因此没有数据,我们必须给客户端一个数据。有数据,反馈客户端还有多少数据。
实现:
文件:
服务器端:
makefile:(文件编译工具,自己去写)
my_conf:(配置文件):设置ip和端口
ser.c:获取连接套接字,完成客户端和服务器端的链接。并启动线程。
socket.c:获取配置文件中的ip和端口,创建套接字,设置端口,获取监听队列上的监听套接字,返回给ser.c
thread.c:创建一个线程函数,通过对客户端发来的命令进行解析,对客户端进行回复。
if(cmd == NULL)
{
send(c,CMD_ERR,strlen(CMD_ERR),0);
continue;
}
(将管道的写端使用dup覆盖标准输出 )
对客户端发来命令的处理步骤:
//解析命令
char * get_cmd(char buff[],char* myargv[])
{
if ( buff == NULL || myargv == NULL )
{
return NULL;
}
char * s = strtok(buff," ");
int i = 0;
while( s != NULL )
{
myargv[i++] = s;
s = strtok(NULL," ");
}
return myargv[0];
}
socket.h#include
#include
#include
#include
#include
#include
#include
#include
int socket_init();
thread.h#include
#include
#include
#include
#include
#include
void start_thread(int c);
ser.c#include "socket.h"
#include "thread.h"
int main()
{
int sockfd = socket_init(); //获取监听队列
if(sockfd == -1)
{
printf("create socket err\n");
exit(0);
}
struct sockaddr_in caddr;
while(1)
{
int len = sizeof(caddr);
int c = accept(sockfd,(struct sockaddr*)&caddr,&len);
if(c < 0)
{
continue;
}
printf("accept c =%d\n",c);
//启动线程
start_thread(c);
}
}
socket.c#include "socket.h"
#define IPS "ipstr="
#define PORT "port="
#define LISMAX "lismax="
struct sock_info
{
char ips[32];//用来存放从配置文件中获取的ip地址,端口,以及listen能获取的监听套接子的个数
short port;
short lismax;
};
int read_conf(struct sock_info *pa)//设置配置文件ip port lismax
{
if(pa == NULL)
{
return -1;
}
FILE *fp = fopen("my.conf","r");//只读方式打开
if(fp == NULL)
{
printf("my.conf not exist\n");
return -1;
}
char buff[128] = {0};
int index = 0;
while(fgets(buff,128,fp) != NULL)//打开my_conf,如果不为空,获取文件中数据
{
index++;
if(strncmp(buff,"#",1)==0)
{
continue;
}
if(strncmp(buff,"\n",1)==0)
{
continue;
}
buff[strlen(buff)-1] = '\0';
//判断ip
if(strncmp(buff,IPS,strlen(IPS)) == 0)
{
strcpy(pa->ips,buff+strlen(IPS));
}
//判断端口
else if(strncmp(buff,PORT,strlen(PORT))==0)
{
pa->port = atoi(buff+strlen(PORT));
}
else if(strncmp(buff,LISMAX,strlen(LISMAX)) == 0)
{
pa->lismax = atoi(buff+strlen(LISMAX));
}
else
{
printf("未识别的配置%d行:%s\n",index,buff);
}
}
fclose(fp);
}
int socket_init()
{
struct sock_info a;
if(read_conf(&a) == -1) //读取配置文件失败
{
printf("read conf err");
return -1;
}
printf("ip:%s\n", a.ips);
printf("port :%d\n",a.port);
printf("lismax : %d\n",a.lismax);
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
printf("create sockfd failed\n");
return sockfd;
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(a.port);;
saddr.sin_addr.s_addr = inet_addr(a.ips);
int res = bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(res == -1)
{
return -1;
}
res = listen(sockfd,a.lismax);
if(res == -1)
{
return -1;
}
printf("res=%d\n",res);
return sockfd;
}
thread.c#include "thread.h"
#include
#define ARG_MAX 10
#define CMD_ERR "arg err"
#define PIPE_ERR "err pipe"
#define FORK_ERR "err fork"
#define OK "ok#"
char *get_cmd(char buff[],char* myargv[])
{
if(buff == NULL||myargv == NULL)
{
return NULL;
}
char *s = NULL;//每次返回的子段
char *p = NULL;//记录当前分割字符串的位置
int i = 0;
s = strtok_r(buff," ",&p);
while(s!=NULL)
{
myargv[i++] = s;
s = strtok_r(NULL," ",&p);
}
return myargv[0];//返回待处理的命令
}
void * work_thread(void *arg)
{
int c = (int)arg;
while(1)
{
char buff[128] = {0};
int n = recv(c,buff,127,0);
if(n<=0)
{
break;
}
//解析命令以及参数
char *myargv[ARG_MAX] = {0};
char *cmd = get_cmd(buff,myargv);
//参数检查
if(cmd == NULL)
{
send(c,CMD_ERR,strlen(CMD_ERR),0);
continue;
}
//判断是不是命令 ---fork+exec
//get ==代表下载 ---自己实现函数 downfile()
//up == 代表是上传 recvfile()
if(strcmp(cmd,"get")==0)
{
// send_file(c,myargv[1]);
}
else if(strcmp(cmd,"up") == 0)
{
}
else
{
//创建无名管道
int pipefd[2];
if(pipe(pipefd) == -1)
{
send(c,PIPE_ERR,strlen(PIPE_ERR),0);
continue;
}
pid_t pid= fork();
if(pid == -1)
{
send(c,FORK_ERR,strlen(FORK_ERR),0);
continue;
}
//fork -- child替换标准输出
if(pid == 0)
{
close(pipefd[0]);
dup2(pipefd[1],1); //管道写端覆盖标准输出
dup2(pipefd[1],2); //管道写端覆盖标准错误输出
execvp(cmd,myargv);
perror("exec err");
close(pipefd[1]);
exit(0);
}
//fork -//下载 -parent read管道
close(pipefd[1]);
wait(NULL);
char read_buff[1024] = {OK};
read(pipefd[0],read_buff+strlen(OK),1021);
close(pipefd[0]);
send(c,read_buff,strlen(read_buff),0);
}
//printf("buff=%s\n",buff);
// send(c,"ok",2,0); //测试收发数据正常
}
printf("client close\n");
close(c);
}
void start_thread(int c)
{
//创建一个线程函数
pthread_t id;
pthread_create(&id,NULL,work_thread,(void*)c);
}
#设置配置文件
#ip地址
ipstr=127.0.0.1
port=6000
lismax=5
all: ser
ser: ser.o socket.o thread.o
gcc -o ser ser.o socket.o thread.o -lpthread
ser.o : ser.c
gcc -c ser.c
socket.o : socket.c
gcc -c socket.c
thread.o:thread.c
gcc -c thread.c -Wpointer-to-int-cast
clean:
rm -rf *.o ser
#include
#include
#include
#include
#include
#include
#include
#include
#define OK "ok#"
char * get_cmd(char buff[],char* myargv[])
{
if ( buff == NULL || myargv == NULL )
{
return NULL;
}
char * s = strtok(buff," ");
int i = 0;
while( s != NULL )
{
myargv[i++] = s;
s = strtok(NULL," ");
}
return myargv[0];
}
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if( sockfd == -1 )
{
exit(0);
}
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if ( res == -1 )
{
close(sockfd);
exit(0);
}
while( 1 )
{
printf("connect>>");
fflush(stdout);
char buff[128] = {0};
fgets(buff,128,stdin);
buff[strlen(buff)-1] = 0;
char cmd_buff[128] = {0};
strcpy(cmd_buff,buff);//备份键盘输入的命令
//解析命令 参数 ,异常检查
char* myargv[10] = {0};
char * cmd = get_cmd(buff,myargv);
if ( cmd == NULL )
{
continue;
}
else if ( strcmp(cmd,"exit") == 0 )//exit 客户端要退出
{
break;
}
else if ( strcmp(cmd,"get") == 0 )
{
//get 下载
recv_file(sockfd,cmd_buff,myargv[1]);
}
else if ( strcmp(cmd,"up") == 0 )
{
//up 上传
}
else
{
//执行通用命令
send(sockfd,cmd_buff,strlen(cmd_buff),0);
char read_buff[1024] = {0};
//读取服务器返回的结果
int num = recv(sockfd,read_buff,1023,0);
if ( num <= 0 )
{
printf("ser close or err\n");
break;
}
if ( strncmp(read_buff,OK,strlen(OK)) == 0 )
{
printf("%s\n",read_buff+strlen(OK));
}
else
{
printf("%s\n",read_buff);
}
}
}
}