#define UPFILE 1
#define DOWNFILE 2
#define COMMAND 3typedef struct Command
{
long type;
char text[128];
}S_Command;class FileTrans
{
public:
void SendFile(char *filename, int sockfd, int flag);
void RecvFile(char *filename, int sockfd, int flag);
};
服务器:
class ServerSocket : public FileTrans
{
public:
ServerSocket(char *ip="127.0.0.1", short port=6000);
~ServerSocket();
void Start();private:
void GetClientLink();
void DealClientData(int sockfd);
void DeleteClentLink(int sockfd);
void DealCommand(int sockfd, char *cmd);private:
int listenfd;
int epfd;
};
const int maxevents = 100;
//构造函数,创建用于监听的socket&epoll的内核事件表
ServerSocket::ServerSocket(char *ip, short port)
{
signal(SIGCHLD, SIG_IGN);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
assert(listenfd != -1);struct sockaddr_in ser
memset(&ser, 0, sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);int res = bind(listenfd, (struct sockaddr*)&ser, sizeof(ser));
assert(-1 != res);listen(listenfd, 5);
epfd = epoll_create(5);
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = listenfd;// 将监听socket添加到内核事件表中
epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &event);
}ServerSocket::~ServerSocket()
{
close(listenfd);
close(epfd);
}void ServerSocket::Start()
{
while(1)
{
struct epoll_event events[maxevents];
int n = epoll_wait(epfd, events, maxevents, -1);
if(n == -1 || n == 0)
{
cout<<"Server Start Fail"<<endl;
break;
}for(int i = 0; i < n; ++i)
{
int fd = events[i].data.fd;
if(fd == listenfd)
{
GetClientLink(); // 获取一个客户端连接
continue;
}
if(events[i].events & EPOLLRDHUP)
{
DeleteClentLink(fd); // 关闭一个客户端连接
continue;
}
if(events[i].events & EPOLLIN)
{
DealClientData(fd); // 处理客户端发送的数据
}
}
}
}void ServerSocket::GetClientLink()
{
struct sockaddr_in cli;
socklen_t len = sizeof(cli);
int c = accept(listenfd, (struct sockaddr*)&cli, &len);
if(c == -1)
{
cout<<"One Client Link Fail"<<endl;
return;
}
struct epoll_event event;
event.events = EPOLLIN | EPOLLRDHUP;
event.data.fd = c;epoll_ctl(epfd, EPOLL_CTL_ADD, c, &event);
}void ServerSocket::DeleteClentLink(int sockfd)
{
close(sockfd);
epoll_ctl(epfd, EPOLL_CTL_DEL, sockfd, NULL);
}void ServerSocket::DealClientData(int sockfd)
{
S_Command data;
memset(&data, 0, sizeof(data));int n = recv(sockfd, &data, sizeof(data), 0);
if(n <= 0)
{
DeleteClentLink(sockfd);
return;
}
char *p = NULL;
switch(data.type)
{
case UPFILE: // 服务器处理客户端上传文件请求
p = strtok(data.text, " ");
p = strtok(NULL, " ");
send(sockfd, "OK", 2, 0);
RecvFile(p, sockfd, 0);
break;
case DOWNFILE: // 服务器处理客户端下载文件请求
p = strtok(data.text, " ");
p = strtok(NULL, " ");
SendFile(p, sockfd, 0);
break;
case COMMAND: // 服务器处理客户端执行命令请求
DealCommand(sockfd, data.text);
break;
default:
break;
}
}void ServerSocket::DealCommand(int sockfd, char *cmd)
{
char *Argv[128] = {0};
int count = 0;
char *p = strtok(cmd, " ");
while(p != NULL)
{
Argv[count++] = p;
p = strtok(NULL, " ");
}if(strncmp(cmd, "cd", 2) == 0)
{
chdir(Argv[1]); //cd xxxx路径 chdir修改工作路径 cd为Argv[0] ,xxxx路径为Argv[1]
send(sockfd, "Command Success\n", strlen("Command Success\n"), 0);
return;
}int fds[2];
pipe(fds); //管道 一端读fds[0] 一端写fds[1]
pid_t pid = fork();
assert(-1 != pid);if(0 == pid) //子进程执行
{
close(fds[0]); //关闭读操作
close(1); //关闭标准输出
close(2); //关闭标准错误dup返回新的文件描述符,和原文件描述符指向相同的文件、管道或网络连接,返回文件描述符是当前可用文件描述符中最小数值,关闭1:标准输出,dup返回当前最小的可用文件描述符,1,这样可以使服务器输出到标准输出里的内容直接发送到与客户端连接的文件描述符上,因此,printf调用的输出将被客户端获得,而不是显示在服务器上
dup(fds[1]);
dup(fds[1]);char path[128] = "/bin/"; //设定路径,调用系统的命令操作
strcat(path, Argv[0]); //链接字符串,/bin/ls
execv(path, Argv); //进程替换write(fds[1], "Comand Not Fount\n", strlen("Comand Not Fount\n"));
exit(0);
}
else //父进程执行
{
close(fds[1]);//关闭写操作
while(1)
{
char buff[1024] = {0};
int n = read(fds[0], buff, 1023);
if(n <= 0)
{
strcpy(buff, "Command Success\n");
send(sockfd, buff, strlen(buff), 0);
break;
}send(sockfd, buff, strlen(buff), 0);
}
}
}
客户端:
class ClientSocket : public FileTrans
{
public:
ClientSocket(char *ip = "127.0.0.1", short port = 6000);
~ClientSocket();
void Start();
private:
void PrintTipsInfo();
private:
int sockfd;
};
ClientSocket::ClientSocket(char *ip, short port)
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);
assert(-1 != sockfd);struct sockaddr_in ser;
memset(&ser, 0, sizeof(ser));
ser.sin_family = AF_INET;
ser.sin_port = htons(port);
ser.sin_addr.s_addr = inet_addr(ip);int res = connect(sockfd, (struct sockaddr*)&ser, sizeof(ser));
assert(-1 != res);
}
ClientSocket::~ClientSocket()
{
close(sockfd);
}
void ClientSocket::Start()
{
while(1)
{
PrintTipsInfo();
char command[128] = {0};
fgets(command, 128, stdin);
command[strlen(command) - 1] = 0;if(strlen(command) == 0)
{
continue;
}if(strncmp(command, "exit", 4) == 0)
{
exit(0);
}S_Command data;
memset(&data, 0, sizeof(data));
strcpy(data.text, command);
if(strncmp(command, "up", 2) == 0)
{
data.type = UPFILE;
send(sockfd, &data, strlen(data.text) + sizeof(data.type), 0);
char buff[128] = {0};
recv(sockfd, buff, 127, 0);
char *p = strtok(data.text, " ");
p = strtok(NULL, " ");
SendFile(p, sockfd, 1);
}
else if(strncmp(command, "down", 4) == 0)
{
data.type = DOWNFILE;
send(sockfd, &data, strlen(data.text) + sizeof(data.type), 0);
char *p = strtok(data.text, " ");
p = strtok(NULL, " ");
RecvFile(p, sockfd, 1);
}
else
{
data.type = COMMAND;
/*if(strncmp(data.text, "ls", 2) == 0)
{
strcat(data.text, " -l");
}*/send(sockfd, &data, strlen(data.text) + sizeof(data.type), 0);
while(1)
{
char buff[1024] = {0};
int n = recv(sockfd, buff, 1023, 0);
if(n <= 0)
{
exit(0);
}
cout<<buff;if(strstr(buff, "Command Success") != NULL)
{
break;
}
}
}
}
}void ClientSocket::PrintTipsInfo()
{
cout<<"**********************File Trans *********************"<<endl;
cout<<"********* ls 显示服务器上的文件列表命令 *********"<<endl;
cout<<**"****** cd 切换服务器上的当前工作目录 *********"<<endl;
cout<<"**** pwd 显示服务器当前工作目录的绝对路径*****"<<endl;
cout<<"***************** down 下载一个文件 ****************"<<endl;
cout<<"****************** up 上传一个文件 ******************"<<endl;
cout<<"InPut: ";
}