实现了一个 shell server的功能,每当有客户端连接的时候,都会为远程客户端分配shell。
使用命令:
启动服务端 ./a.out server
启动客户端: ./a.out client
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int run_shell(int cmd_pipe, int echo_pipe)
{
int pid = -1;
pid = fork();
if(pid < 0)
{
perror("fork child error\n");
return 0;
}
else if(pid == 0)
{
dup2(cmd_pipe, STDIN_FILENO);
dup2(echo_pipe, STDOUT_FILENO);
dup2(echo_pipe, STDERR_FILENO);
//system("sh");
execl("/bin/sh","/bin/sh",(char *)0);
exit(0);
return 0;
}
else
{
//waitpid(pid, 0, 0);
return pid;
}
}
const char g_end_cmd[] = "\03\n";//"^C\n"
void *client_work_thread(void *pclientfd)
{
printf("client_work_thread for connect 0x%x\n", (int)pclientfd);
int clisock = (int)pclientfd;
if(fcntl(clisock, F_SETFL, fcntl(clisock, F_GETFL) | O_NONBLOCK) == -1)
{
perror("cann't set noblock socket\n");
close(clisock);
return 0;
}
fd_setrset;
int fdpipe_send_cmd[2];
int fdpipe_recv_echo[2];
if(pipe(fdpipe_send_cmd) == -1)
{
close(clisock);
return 0;
}
if(pipe(fdpipe_recv_echo) == -1)
{
close(clisock);
close(fdpipe_send_cmd[0]);
close(fdpipe_send_cmd[1]);
return 0;
}
int fscmd = fdpipe_send_cmd[1];
int fsecho = fdpipe_recv_echo[0];
int child_pid = run_shell(fdpipe_send_cmd[0], fdpipe_recv_echo[1]);
int fdmaxp1 = (fsecho > clisock) ? (fsecho + 1) : (clisock + 1);
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
char pipebuf[1024] = "";
while(1)
{
FD_ZERO(&rset);
FD_SET(clisock, &rset);
FD_SET(fsecho, &rset);
memset(pipebuf, 0x00, sizeof(pipebuf));
int nret = select(fdmaxp1, &rset, 0, 0, &tv);
if(nret == -1)
{
break;
}
if(FD_ISSET(fsecho, &rset))
{
read(fsecho, pipebuf, 1024);
if(send(clisock, pipebuf, strlen(pipebuf), 0) < 0)
{
perror("send error\n");
write(fscmd, g_end_cmd, sizeof(g_end_cmd));
break;
}
}
if(FD_ISSET(clisock, &rset))
{
if(recv(clisock, pipebuf, 1024, 0) <= 0)
{
perror("clisock closed\n");
write(fscmd, g_end_cmd, sizeof(g_end_cmd));
break;
}
printf("send cmd -- %s\n", pipebuf);
write(fscmd, pipebuf, strlen(pipebuf));
}
}
close(clisock);
close(fdpipe_send_cmd[0]);
close(fdpipe_send_cmd[1]);
close(fdpipe_recv_echo[0]);
close(fdpipe_recv_echo[1]);
kill(child_pid, SIGKILL);
waitpid(child_pid, 0);
return 0;
}
const unsigned short k_SERVER_PORT = 3434;
void *server_thread(void *para)
{
struct sockaddr_in servaddr;
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0x00, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(k_SERVER_PORT);
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
close(listenfd);
perror("bind error\n");
return 0;
}
if(listen(listenfd, 10) == -1)
{
close(listenfd);
perror("listen error\n");
return 0;
}
printf("listen on %d\n", k_SERVER_PORT);
int clifd = -1;
pthread_t clith;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
while((clifd = accept(listenfd, 0, 0)) != -1)
{
//client work thread
printf("accept new connect.\n");
pthread_create(&clith, &attr, client_work_thread, (void *)clifd);
}
pthread_attr_destroy(&attr);
}
void *client_thread(void *para)
{
struct sockaddr_in servaddr;
int clifd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0x00, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(k_SERVER_PORT);
if(connect(clifd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
perror("connect error\n");
close(clifd);
return 0;
}
char sndbuf[1024] = "";
while(1)
{
scanf("%s", sndbuf);
strcat(sndbuf, "\n");
send(clifd, sndbuf, strlen(sndbuf), 0);
recv(clifd, sndbuf, 1024, 0);
printf(sndbuf);
}
close(clifd);
return 0;
}
int main(int argc, const char** argv)
{
if(argc == 2)
{
if(strstr(argv[1], "client"))
{
printf("start client mode\n");
client_thread(0);
}
else
{
printf("start server mode\n");
server_thread(0);
}
}
}