связь между клиентом и сервером, выполнение команд - PullRequest
0 голосов
/ 29 января 2019

Я пытаюсь сделать командную строку, основанную на сокетной связи. Моя единственная проблема заключается в том, что после выполнения 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;
}

sever.c

#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 голосов
/ 04 февраля 2019

Если клиент отправляет pwd, сервер может получить p w d или pw d или pwd и т. Д.

По моему мнению, если клиент захочетчтобы отправить 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;
}
0 голосов
/ 29 января 2019

Цикл

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

эффективно выполняется один раз.Причина в том, что успешный execvp заменяет код любыми vector_args запросами, и выполненный процесс просто завершается по завершении.

Если я правильно понимаю ваши цели (один процесс насоединения, выполняя внешние команды в цикле), вам понадобится еще один форк, по аналогии с

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