客户端和服务器之间的通信,执行命令

时间:2019-01-29 16:40:04

标签: c fork exec

我正在尝试基于套接字通信来创建命令行。我唯一的问题是,执行exexvp之后(并且数据正在客户端打印),客户端关闭并且我想让他活着。

这是我的代码:

client.c

#include <unistd.h> 
#include <stdio.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <string.h> 
#include <sys/types.h>
#include <netdb.h>
#define PORT_NUMBER 1754
#define HOST_NUMBER

void error(const char *msg) 
{ 
    perror(msg); 
    exit(0); 
}

int main(int argc, char *argv[]) 
{ 
    int sockfd, port_number, n;     
    struct sockaddr_in serv_addr; 
    struct hostent *server;

    char buffer[256];

    if (argc < 3) { 
        //fprintf(stderr, "usage %s hostname port\n", argv[0]); 
        //first parameter is ip address
        printf("usage %s hostname port\n", argv[0]);        
        exit(0); 
    } 
    port_number = atoi(argv[2]);                        

    sockfd = socket(AF_INET, SOCK_STREAM, 0); 

    if (sockfd < 0 ) 
        error("ERROR opening socket!Socket failed!"); 

    printf("Trying to connect...\n");
    server = gethostbyname(argv[1]);  //ip address

    if (server == NULL) { 
        error( "ERROR, no such host"); 
        //fprintf(stderr, "ERROR, no such host\n");  exit(0); 
    } 
    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;  //AF_UNIX

    bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);

    serv_addr.sin_port = htons(port_number); 

    if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
        error("ERROR connecting"); 

    printf("Connected!\n");
    printf("%s_>\n",argv[1]);

    while(1) {
        printf("Please enter the message: "); //THE CLIENT MUST WRITE A COMMAND

        fgets(buffer, 256, stdin);     //apo stdin sto buffer
        n = write(sockfd, buffer, strlen(buffer)); //apo buffer sto socket

        if(n < 0 ) {
            error("ERROR writing to socket");
        }
        bzero(buffer, 256);

        if ( recv(sockfd, buffer, 256, 0) < 0) {
            printf("Server closed connection\n");
        }
        printf("%s\n", buffer);
    }
    return 0;
}

服务器

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>

void parse(char *vector_args[20], char *buffer){
    buffer[strcspn(buffer, "\n")] =0;

    int i=0;
    char * pch;

    pch = strtok (buffer," "); 

    while (pch != NULL )
    {
        vector_args[i]=pch;                
        printf (" %s\n",pch);
        pch = strtok (NULL, " ");          
        i++;
    }

    vector_args[i]=NULL;                             
    int k=0;
    for(k=0; k<=i; k++) {
        printf("vector %d = %s \n",k,vector_args[k]);
    }
}

int main(int argc, char *argv[])
{
    int sockfd, newsockfd, portno;
    socklen_t clilen;
    char buffer[256];
    struct sockaddr_in serv_addr, cli_addr;
    int n;
    char str[INET_ADDRSTRLEN];

    char *vector_args[20];

    int status;
    char *fd[2];
    if (argc < 2)
    {
        fprintf(stderr, "No port provided\n");
        exit(1);
    }
    unlink("sockfd");    //remove any old socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
        error("ERROR opening socket");
    bzero((char *) &serv_addr, sizeof(serv_addr));
    portno = atoi(argv[1]);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(portno);
    if (bind(sockfd,(struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0)
        error("ERROR on binding");
    int l = listen(sockfd, 5);
    if (l < 0) 
    { 
            error("listen failed!"); 

    }
    clilen = sizeof(cli_addr);
    printf( "Server waiting for a connection...\n " );
    while(1) {
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        if (newsockfd < 0)
            error("ERROR on accept");

        if (inet_ntop(AF_INET, &cli_addr.sin_addr, str, INET_ADDRSTRLEN) == NULL) {
            fprintf(stderr, "Could not convert byte to address\n");
            exit(1);
        }

        fprintf(stdout, "Connected!\nThe client address is :%s\n", str);

        //fork new process
        int pid = fork();

        if (pid == -1 ) {
            error("ERROR in new process creation");
            close(newsockfd);
            continue;
        }else if( pid != 0){
            //parent process
            close(newsockfd);//h edw h prin to continue
            printf( " I am parent process %d\n " ,getpid());     //BGALE
            if (wait(&status)== -1) /* Wait for child*/
            {
                perror( " wait " );
            }
            check_child_exit(status);
            continue;
         }else if (pid == 0) {
              //child process
            close(sockfd);

            bzero(buffer, 256);
            while(1) {
                n = read(newsockfd, buffer, 255); //apo socket ston buffer 
                if (n < 0 )
                    error("ERROR reading from socket");

                printf("Here is the message: %s\n", buffer);
                n = write(newsockfd, "I got your message", 18);
                bzero(buffer, 256);
                close(1);                //close stdin
                dup2( newsockfd, 1); 
                close(0);                //close stdout
                dup2( newsockfd, 0);     

                parse(vector_args,buffer);

                execvp(vector_args[0] , vector_args );          

                perror( " execvp " );
                exit(EXIT_FAILURE);

                bzero(buffer, 256);
            }
            close(newsockfd);
            break;
       }   
    }
}

您有任何想法如何更改代码以使其正常工作?

2 个答案:

答案 0 :(得分:0)

循环

    while (1) {
        ....
        execvp(....);
    }

有效执行一次。原因是成功的execvp vector_args所请求的内容替换代码,执行的过程仅在完成后退出。

如果我正确理解了您的目标(每个连接一个进程,在循环中执行外部命令),则您需要再进行一次分叉,

    while (1) {
        ....
        if ((pid = fork()) == 0) {
            execvp(....);
        } else if (pid > 0) {
            waitpid(....);
        } else {
            handle_error();
        }
    }

答案 1 :(得分:0)

如果客户端发送pwd,则服务器可能会接收p w dpw dpwd

我认为,如果客户端要发送pwd,则客户端应发送pwd\n,服务器将读取命令,直到\n。如果服务器要发送123,则服务器应发送123\0,客户端将读取直到\0。我写一个小例子,您可以从中学到东西。服务器代码将继续,直到客户端退出。

server.c

#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

void parse(char** argv, char* buffer) {
  int i = 0;
  argv[i] = strtok(buffer, " ");

  while (argv[i] != NULL) argv[++i] = strtok(NULL, " ");
}

void handle_client(int con_socket) {
  for (;;) {
    char buf[1024];
    ssize_t i = 0;
    for (;;) {
      ssize_t ret = read(con_socket, buf + i, 1);
      if (ret == 0) return;
      if (buf[i] == '\n') {
        buf[i] = '\0';
        break;
      }
      ++i;
    }

    int pipe_fd[2];
    pipe(pipe_fd);

    if (fork() == 0) {
      close(con_socket);
      dup2(pipe_fd[1], 1);
      close(pipe_fd[0]);
      close(pipe_fd[1]);

      char* argv[25];
      parse(argv, buf);

      execvp(argv[0], argv);
      exit(EXIT_FAILURE);
    } else {
      close(pipe_fd[1]);
      for (;;) {
        ssize_t ret = read(pipe_fd[0], buf, sizeof(buf));
        if (ret == 0) {
          write(con_socket, "", 1);
          break;
        }
        write(con_socket, buf, ret);
      }
      wait(NULL);
    }
  }
}

int main() {
  const char* server_ip = "127.0.0.1";
  uint16_t server_port = 6666;

  struct sockaddr_in server_addr;
  bzero(&server_addr, sizeof server_addr);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(server_port);
  inet_pton(AF_INET, server_ip, &server_addr.sin_addr);

  int listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  int opt = 1;
  setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  bind(listen_socket, (struct sockaddr*)(&server_addr),
       (socklen_t)(sizeof server_addr));
  listen(listen_socket, 5);

  for (;;) {
    int con_socket = accept(listen_socket, NULL, NULL);
    if (fork() > 0) {
      close(con_socket);
      wait(NULL);
      continue;
    } else {
      close(listen_socket);
      handle_client(con_socket);
      close(con_socket);
      break;
    }
  }
  return 0;
}

client.c

#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
  const char* server_ip = "127.0.0.1";
  uint16_t server_port = 6666;

  struct sockaddr_in server_addr;
  bzero(&server_addr, sizeof server_addr);
  server_addr.sin_family = AF_INET;
  server_addr.sin_port = htons(server_port);
  inet_pton(AF_INET, server_ip, &server_addr.sin_addr);

  int sockfd = socket(AF_INET, SOCK_STREAM, 0);

  connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

  for (;;) {
    printf(">> ");
    char buffer[256];
    fgets(buffer, 256, stdin);
    if (strlen(buffer) == 0) continue;
    write(sockfd, buffer, strlen(buffer));

    for (;;) {
      ssize_t ret = recv(sockfd, buffer, 256, 0);
      buffer[ret] = '\0';
      printf("%s", buffer);
      if (buffer[ret - 1] == '\0') break;
    }
  }
  return 0;
}