套接字操作中的sigpio来自哪里?

hrirmatl  于 2022-10-04  发布在  Linux
关注(0)|答案(1)|浏览(129)

我正在尝试使用p线程编写一个简单的多线程信使程序。我正在将sockfd添加到线程安全的链表中,并尝试将消息从每个客户端的处理程序线程发送到所有其他客户端。我预计过时的连接将从列表中删除,它可以正常工作,因为我采用了“C++并发操作”中的代码。使用lldb运行代码后,我发现在断开客户端连接后,服务器从信号13(即SIGPIPE)崩溃。我不知道这会在哪里发生,因为我希望WRITE返回-1,有人能帮忙吗?

Server.cpp

void *conn_handler(void *);
void send_msg(std::pair<uint32_t, char *> reply_pair);
multithread_list<int> adress_list;

int main(int argc, char *argv[]) {
  (void)argc;
  (void)argv;
  int sockfd;
  uint16_t portno;
  unsigned int clilen;
  struct sockaddr_in serv_addr, cli_addr;

  /* First call to socket() function */
  sockfd = socket(AF_INET, SOCK_STREAM, 0);

  if (sockfd < 0) {
    perror("ERROR opening socket");
    exit(1);
  }

  /* Initialize socket structure */
  bzero((char *)&serv_addr, sizeof(serv_addr));
  portno = 5001;

  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = INADDR_ANY;
  serv_addr.sin_port = htons(portno);

  /* Now bind the host address using bind() call.*/
  if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
    perror("ERROR on binding");
    exit(1);
  }

  /* Now start listening for the clients, here process will
   * go in sleep mode and will wait for the incoming connection
   */
  while (true) {
    listen(sockfd, 5);
    clilen = sizeof(cli_addr);

    /* Accept actual connection from the client */
    int newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen);
    adress_list.push_front(newsockfd);
    pthread_t thread;

    if (pthread_create(&thread, nullptr, conn_handler, (void *)&newsockfd) < 0) {
      perror("ERROR creating thread.");
    }
    pthread_detach(thread);
  }
  return 0;
}
void *conn_handler(void *newsockfd_v) {
  int newsockfd = *reinterpret_cast<int *>(newsockfd_v);
  char buffer[256];
  if (newsockfd < 0) {
    perror("ERROR on accept");
    exit(1);
  }
  while (true) {
    /* If connection is established then start communicating */
    bzero(buffer, 256);
    ssize_t n = read(newsockfd, buffer, 255);
    if (n < 0) {
      printf("break");
      break ;
    }
    data *user_data = buffer_to_data(buffer);
    printf("Here is the message: %sn", user_data->body);
    printf("current newsockfd = %dn", newsockfd);
    /* Write a response to the client */
    send_msg(data_to_buffer(user_data));
  }
  return nullptr;
}

void send_msg(std::pair<uint32_t, char *> reply_pair) {
  adress_list.remove_if([reply_pair](int sock) {
    ssize_t n = write(sock, reply_pair.second, reply_pair.first);
    if (n < 0) {
      return true;
    }
    return false;
  });
}

Client.cpp


# define BUFF_SIZE 256

void remove_enter_symbol(char *buffer, size_t buff_size) {
  if (buffer == nullptr) exit(1);
  for (size_t i = 0; i < buff_size; i++) {
    if (buffer[i] == 'n') {
      buffer[i] = '0';
      break;
    }
  }
}

size_t get_word_size(const char *buffer, size_t buff_size) {
  if (buffer == nullptr) exit(1);
  size_t counter = 0;
  for (size_t i = 0; i < buff_size; ++i) {
    if (buffer[i] != '0')
      counter++;
    else
      break;
  }
  return counter;
}

void *listen_server(void *sock) {
  int sockfd = *reinterpret_cast<int *>(sock);
  char *receive_buffer = new char[256];
  while (true) {
    bzero(receive_buffer, BUFF_SIZE);
    ssize_t n = read(sockfd, receive_buffer, BUFF_SIZE - 1);
    if (n < 0) {
      perror("ERROR reading from socket");
      break;
    }
    server_data *d = buffer_to_struct(receive_buffer);
    printf("[%s]  ", d->date);
    printf("%s: ", d->name);
    printf("%sn", d->body);
  }
  return nullptr;
}
int main(int argc, char *argv[]) {
  (void)argc;
  (void)argv;
  ssize_t sockfd, n;
  uint16_t portno;
  struct sockaddr_in serv_addr;
  struct hostent *server;

  char name_buffer[BUFF_SIZE];
  char body_buffer[BUFF_SIZE];
  data user_data;

  if (argc < 3) {
    fprintf(stderr, "usage %s hostname portn", argv[0]);
    exit(0);
  }

  portno = (uint16_t)atoi(argv[2]);

  /* Create a socket point */
  sockfd = socket(AF_INET, SOCK_STREAM, 0);

  if (sockfd < 0) {
    perror("ERROR opening socket");
    exit(1);
  }

  server = gethostbyname(argv[1]);

  if (server == NULL) {
    fprintf(stderr, "ERROR, no such hostn");
    exit(0);
  }

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

  /* Now connect to the server */
  if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
    perror("ERROR connecting");
    exit(1);
  }

  /* Now ask for a message from the user, this message
   * will be read by server
   */

  pthread_t thread;

  if (pthread_create(&thread, nullptr, listen_server, (void *)&sockfd) < 0) {
    perror("ERROR creating thread.");
  }
  pthread_detach(thread);

  printf("Please enter the name: ");
  bzero(name_buffer, BUFF_SIZE);
  if (fgets(name_buffer, BUFF_SIZE - 1, stdin) == NULL) {
    perror("ERROR reading from stdin");
    pthread_kill(thread, -1);
    exit(1);
  }
  remove_enter_symbol(name_buffer, BUFF_SIZE);
  user_data.name = name_buffer;
  user_data.name_size = get_word_size(name_buffer, BUFF_SIZE);

  while (true) {

    printf("Please enter the message: ");
    bzero(body_buffer, BUFF_SIZE);
    if (fgets(body_buffer, BUFF_SIZE - 1, stdin) == NULL) {
      perror("ERROR reading from stdin");
      pthread_kill(thread, -1);
      exit(1);
    }
    remove_enter_symbol(body_buffer, BUFF_SIZE);
    user_data.body = body_buffer;
    user_data.body_size = get_word_size(body_buffer, BUFF_SIZE);

    char *buff_to_send = struct_to_buffer(&user_data);

    /* Send message to the server */
    n = write(sockfd, buff_to_send, BUFF_SIZE);

    if (n < 0) {
      perror("ERROR writing to socket");
      pthread_kill(thread, -1);
      exit(1);
    }
  }
  return 0;
}
63lcw9qa

63lcw9qa1#

在断开客户端连接后,服务器从信号13(即SIGPIPE)崩溃

当您尝试写入打开但不再连接到任何内容的文件描述符时,会引发SIGPIPE。当读取端关闭时,使用管道可以很容易地实现这一点。这就是它的助记符。在类似的情况下,插座也可能发生这种情况。

我不知道这会在哪里发生,因为我希望WRITE返回-1

write()可能确实返回-1,或者如果您处理SIGPIPE,会返回-1。这是write()的Linux手册页面的相关部分:

ERRORS

[...]

       EPIPE  fd is connected to a pipe or socket whose reading end is
              closed.  When this happens the writing process will also
              receive a SIGPIPE signal.  (Thus, the write return value
              is seen only if the program catches, blocks or ignores
              this signal.)

相关问题