【问题标题】:communication between client and server,executiolg commands客户端和服务器之间的通信,执行命令
【发布时间】:2019-01-29 16:40:04
【问题描述】:

我正在尝试基于套接字通信执行命令行。我唯一的问题是执行 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;
}

服务器.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;
       }   
    }
}

您有什么想法可以更改我的代码以使其正常工作吗?

【问题讨论】:

    标签: c fork exec


    【解决方案1】:

    循环

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

    有效执行一次。原因是成功的execvp替换代码为vector_args请求的任何内容,完成后执行的进程就退出了。

    如果我正确理解了您的目标(每个连接一个进程,在循环中执行外部命令),您还需要一个 fork,类似于

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

    【讨论】:

    • 我刚试了下,运行不正常!只有命令 execvp();我会把第二个叉子的孩子放进去吗:
    【解决方案2】:

    如果客户端发送pwd,服务器可能会接收pwdpwdpwd等等。

    在我看来,如果客户端要发送pwd,客户端应该发送pwd\n,服务器将读取命令直到\n。如果服务器要发送123,服务器应该发送123\0,客户端将读取直到\0。我写了一个小例子,你可以借鉴一下。服务器代码将继续执行,直到客户端退出。

    服务器.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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-16
      相关资源
      最近更新 更多