C: 处理 `cd ..` 和服务器应用程序上的其他命令并返回反馈给客户端

标签 c linux server client-server

所以我有服务器/客户端应用程序在运行。到目前为止,我可以很好地与服务器通信。我可以让它处理 ls 命令,以便客户端获取文件列表。在这里,我偶然发现了一个问题,我想在服务器中输入各种命令,例如 cd ..mvcp cd directory 以便服务器可以处理它们,客户端将获得有关这些操作的反馈。我认为代码会在这些行之间:

message_size = recv(socket_fd, input, sizeof(input)/sizeof(input[0]), 0);
if(message_size > 0) {
  /* Process incoming message, add end of the line sign */
  input[message_size] = '\0';

  /* Process command and get a response from it */
  fp = popen(input, "r");
  if(fp == NULL)
    fprintf(stderr, "popen() failed: %s\n", strerror(errno));
  else {

    // IS THIS THE RIGHT APPROACH??
    if(strcmp(input, "ls") == 0) {
      while((c = getc(fp)) != EOF) {
        output[i] = c;
        i++;
      }
    i = 0;
    send_message(socket_fd, output);
   }
   else if(strcmp(input, "cd ..") == 0) {
      send_message(socket_fd, "cd ..");
   }
 }

 pclose(fp);

快速解释:input 是服务器从客户端接收的内容。这可以是 cd ..send_message 只是向客户端发送一些信息的函数 - 没什么大不了的。 fp 是一种 FILE *

我如何区分各种命令,从它们那里获得反馈,尤其是 - 从客户端(如 asdf)获得有关错误插入命令的反馈。我的想法是,使用 strcmp 我可以在客户端上进行各种处理,但由于某种原因,当我键入 ls 时,我的客户端卡住了。

客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>

#define MAX_SIZE 10000

int main(int argc, char* argv[])
{
  int socket_fd, port_number;
  struct sockaddr_in serv_addr;
  struct hostent *server;
  char buffer[MAX_SIZE];
  int rc;

  if(argc<2) {
    fprintf(stderr,"Incorrect arguments input\n");
    exit(0);
  }

  port_number = 12345;

  server = gethostbyname(argv[1]);

  socket_fd = socket(AF_INET, SOCK_STREAM, 0);
  if(socket_fd < 0) {
    perror("Error opening socket");
    exit(1);
  }

  bzero((char*) &serv_addr, sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(port_number);
  bcopy((char*) server->h_addr,(char *) &serv_addr.sin_addr.s_addr,sizeof(server->h_length));

  if(connect(socket_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
      perror("Error connecting");
      exit(1);
  }

  enum {
    INIT_STATE,
    READY_STATE
  } serv_state = INIT_STATE;

  #define check_serv_state(str, st) \
   (strncmp(str, #st, sizeof(#st) - 1) == 0)

  for(;;) {
    memset(buffer, 0, sizeof(buffer));
    rc = recv(socket_fd, buffer, sizeof(buffer), 0);
    if(rc<0) {
      perror("Error reading back from server");
      exit(1);
    }
    else if(rc == 0) {
      printf("The server has been disconnected. Quitting.\n");
      exit(0);
    }

    if(serv_state == INIT_STATE) {
      char *part = strtok(buffer,"\n");
      do {
    if(check_serv_state(part, READY)) {
      printf("Server is ready\n");
      serv_state = READY_STATE;
    }
    else 
      printf("Server: [[[%s]]]\n", part);
      } while((part = strtok(NULL, "\n")));

      if(serv_state != READY_STATE)
     continue;
      } else
     printf("#server: %s", buffer);

      memset(buffer, 0, sizeof(buffer));
      printf("#client: ");
      fgets(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, stdin);

      if(send(socket_fd, buffer, strlen(buffer), 0) < 0)
    {
      perror("Error sending message");
      exit(1);
    }
    }

  close(socket_fd);
  return 0;
}

编辑:

正如@Olaf Dietsche 所说,这是 fgets 的错误。现在我想知道为什么服务器不处理 cd .. 命令。

最佳答案

除非您的服务器正在发送一些欢迎消息,否则客户端会“卡住”,因为它等待来自服务器的输入

for (;;) {
    memset(buffer, 0, sizeof(buffer));
    rc = recv(socket_fd, buffer, sizeof(buffer), 0);

同时,服务器正在等待客户端的输入。所以双方都在等待对方。这就是为什么没有进展的原因。


要解决此问题,您必须首先读取用户的输入,然后将此输入从客户端发送到服务器。例如。将其从循环的末尾移动到循环的开头

printf("#client: ");
fgets(buffer, sizeof(buffer)/sizeof(buffer[0]) - 1, stdin);

if (send(socket_fd, buffer, strlen(buffer), 0) < 0) {
    perror("Error sending message");
    exit(1);
}

另一个陷阱可能是 fgets

Parsing stops if end-of-file occurs or a newline character is found, in which case str will contain that newline character.

由于您发送了整个缓冲区,包括最后的换行符,服务器也必须检查这个换行符

if (strcmp(input, "ls\n") == 0) {

或者,您可以在向服务器发送请求之前剥离它

fgets(buffer, sizeof(buffer) / sizeof(buffer[0]) - 1, stdin);
int len = strlen(buffer);
if (buffer[len - 1] == '\n') {
    buffer[len - 1] = 0;
    --len;
}

if (send(socket_fd, buffer, len, 0) < 0) {

cd 命令在某种意义上是特殊的,它只改变调用进程中的目录。当您使用 popen ,该命令将由子进程处理

The popen() function opens a process by creating a pipe, forking, and invoking the shell.
...
The command argument is a pointer to a null-terminated string containing a shell command line. This command is passed to /bin/sh using the -c flag; interpretation, if any, is performed by the shell.

这意味着,服务器调用 popen,这会创建 另一个 进程,而这个其他进程执行 chdir

如果你想让服务器进程改变目录,你不能使用popen,而是使用chdir。在服务器本身。

关于C: 处理 `cd ..` 和服务器应用程序上的其他命令并返回反馈给客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39806337/

相关文章:

c - 指针指向指针的正确用法

linux - 为什么 strace 不显示 HDD IOCTL 系统调用?

linux - OpenStack float IP 关联在底层是如何工作的?

php - 如何查看 Linux 服务器中所有命令的控制台历史记录?

Eclipse 的 Tomcat 给出 404,而 WAR 文件有效 - 以前的解决方案不起作用

c - c中的内存重新分配

C编程将数组变成图像

c - 如何在 C 中从 char** 转换为 char*?

linux - 在Linux中,用户空间如何不能访问内核空间?

node.js - Apache 和 Node 在端口 80 上