(1)ls命令执行:服务器端执行ls命令,服务器端fork复制产生子进程,在把子进程替换成ls(exec),服务器端发给客户端
(2)rm命令执行:fork客户端发给服务器端
(3)为了防止客户端和服务器端不能交互,所以当每次执行命令时候,客户端给服务器端发送"ok#…"(仅仅代表命令执行成功,不代表其他)
(4)无名管道:子进程把输出信息写入无名管道中,父进程从无名管道中把信息读出来,然后发送给客户端,客户端在打印出来。
dup方法:复制文件描述符
先创建管道,在复制一下,管道就会被自动复制到子进程中
(5)服务器端:输入客户端发送过来的命令,然后解析命令
客户端代码:
#include
#include
#include
#include
#include
#include
#include
#include
int conn_ser();
char*get_cmd(char buff[],char *myargv[]);
int main()
{
int sockfd=conn_ser();
if(sockfd==-1)
{
printf("connect ser failed\n");
exit(0);
}
while(1)
{
char buff[128]={0};
printf("connect 127.0.0.1>>");
fflush(stdout);
fgets(buff,128,stdin);
buff[strlen(buff)-1]=0;
char send_buff[128]={0};
strcpy(send_buff,buff);
char *myargv[10]={0};//解析的命令和参数
char*cmd=get_cmd(buff,myargv);
if(cmd==NULL)
{
continue;
}
if(strcmp(cmd,"end")==0)
{
break;
}
else if(strcmp(cmd,"get")==0)
{
//下载
}
else if(strcmp(cmd,"up")==0)
{
//上传
}
else//和服务器交互的命令
{
send(sockfd,send_buff,strlen(send_buff),0);
char recv_buff[1024]={0};
int res=recv(sockfd,recv_buff,1023,0);
if(res<=0)
{
printf("ser close\n");
break;
}
if(strncmp(recv_buff,"ok#",3)==0)
{
printf("%s\n",recv_buff+3);
}
else
{
printf("cmd run err\n");
}
}
}
close(sockfd);
}
char*get_cmd(char buff[],char *myargv[])
{
if(buff==NULL||myargv==NULL)
{
return NULL;
}
int i=0;
char*s=strtok(buff,"");
while(s!=NULL)
{
myargv[i++]=s;
s=strtok(NULL,"");
}
return myargv[0];
}
int conn_ser()
{
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1)
{
return -1;
}
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)
{
return -1;
}
return sockfd;//创建套接字失败或者链接服务器失败就会返回-1
}
服务器端口:
#include"work_thread.h"
#include
#define MAX_ARG 10//最大参数个数
char*get_cmd(char buff[],char*myargv[])//解析buff,并且得到buff 中执行的命令,命令一般都在第一个字段,返回第一个字段
{
//分割字符
if(buff==NULL)
{
return NULL;
}
char *p=NULL;//用来定义分割字符串的位置
int i=0;//定义给数组的第几个元素进行赋值
char*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;
if(c<0)
{
pthread_exit(NULL);
//return;
}
while(1)
{
char buff[128]={0};//保存客户端发送过来的命令(ls rm,ge t a.c...)
int num=recv(c,buff,127,0);//接受套接字
if(num<=0)//客户端关闭
{
break;
}
char*myargv[MAX_ARG]={0};
char*cmd=get_cmd(buff,myargv);
if(cmd==NULL)
{
send(c,"err",3,0);
continue;
}
if(strcmp(cmd,"get")==0)
{
//下载send_file(c);
}
else if(strcmp(cmd,"up")==0)
{
//上传recv_file();
}
else//客户端要和服务器端交互
{
//fork+exec;
int pipefd[2];//pipefd[0],读端,pipefd[1],写端,父> 进程是读端,子进程是写端
if(pipe(pipefd)==-1)//创建管道
{
send(c,"err",3,0);//创建管道失败
continue;
}
pid_t pid=fork();//fork产生子进程
if(pid==-1)
{
send(c,"err",3,0);
continue;
}
if(pid==0)
{
dup2(pipefd[1],1);//管道文件描述符的文件拷贝到> 屏幕,屏幕就会显示
dup2(pipefd[1],2);//原来打印到屏幕的信息会写在> 管道里面
close(pipefd[0]);
execvp(cmd,myargv);
perror("not find cmd");//当命令执行失败的时候执
行这个
exit(0);
}
close(pipefd[1]);
wait(NULL);
char read_pipe[1024]={"ok#"};
read(pipefd[0],read_pipe+3,1020);
send(c,read_pipe,strlen(read_pipe),0);
close(pipefd[0]);
}
}
close(c);
printf("one client close\n");
}
void thread_start(int c)
{
pthread_t id;
pthread_create(&id,NULL,work_thread,(void*)c);
}