无法让套接字保持活动状态并接收数据

问题描述 投票:0回答:1

我想使用此套接字打开连接,

Fork
它并保持打开状态,直到连接被我或客户端程序终止。

目前我只能让它打开,然后收到一条消息并立即关闭,或者保持打开状态但无法检索任何数据,原因我不知道。

下面的代码主要是教程,但最后我尝试使用 while 循环来读取 select 函数,直到准备好读取消息。然后我只希望它在收到该字符串时打印该字符串并且不关闭。

我一直在弄乱这段代码,我真的很累,如果我弄乱了一些东西,我很抱歉。

有没有办法让我创建的

Fork
函数在内部有一个 while(1) 循环,仅检查套接字是否收到消息?

void *socket_handler_thread(void *x_void_ptr)
{
  int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
  struct addrinfo hints, *servinfo, *p;
  struct sockaddr_storage their_addr; // connector's address information
  socklen_t sin_size;
  struct sigaction sa;
  int yes = 1;
  char s[INET6_ADDRSTRLEN];
  int rv;

  memset(&hints, 0, sizeof hints);
  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE; // use my IP

  if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0)
  {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));

  }

// loop through all the results and bind to the first we can
  for (p = servinfo; p != NULL; p = p->ai_next)
  {
    if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
    {
      perror("server: socket");
      continue;
    }

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
    {
      perror("setsockopt");
      exit(1);
    }

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1)
    {
      close(sockfd);
      perror("server: bind");
      continue;
    }

    break;
  }

  freeaddrinfo(servinfo); // all done with this structure

  if (p == NULL)
  {
    fprintf(stderr, "server: failed to bind\n");
    exit(1);
  }

  if (listen(sockfd, BACKLOG) == -1)
  {
    perror("listen");
    exit(1);
  }

  sa.sa_handler = sigchld_handler; // reap all dead processes
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = SA_RESTART;
  if (sigaction(SIGCHLD, &sa, NULL) == -1)
  {
    perror("sigaction");
    exit(1);
  }

  printf("server: waiting for connections...\n");

  int socket_fd, result;
  fd_set readset;
  struct timeval tv;
  /* Wait up to five seconds. */
  tv.tv_sec = 0;
  tv.tv_usec = 100000;

  while (1)
  {  // main accept() loop
    sin_size = sizeof their_addr;
    new_fd = accept(sockfd, (struct sockaddr *) &their_addr, &sin_size);

    if (new_fd == -1)
    {
      perror("accept");
      continue;
    }

    inet_ntop(their_addr.ss_family,
        get_in_addr((struct sockaddr *) &their_addr), s, sizeof s);
    printf("server: got connection from %s\n", s);

    do
    {

      FD_ZERO(&readset);
      FD_SET(new_fd, &readset);
      result = select(new_fd + 1, &readset, NULL, NULL, &tv);
      printf("Stuck result = %i  ::: new_fd = %i \n\r", result, new_fd);
    } while (result == -1 && errno == EINTR);

    if (result > 0)
    {
      if (FD_ISSET(new_fd, &readset))
      {
        if (!fork())
        { // this is the child process

          printf("WORKED!");

          Fork(sockfd, new_fd);

        }
        //close(new_fd);  // parent doesn't need this
      }

      result = recv(socket_fd, some_buffer, some_length, 0);
      if (result == 0)
      {
        /* This means the other side closed the socket */
        //close(socket_fd);
      }
      else
      {
        /* I leave this part to your own implementation */
      }

    }
    else if (result < 0)
    {
      printf("Connection closed!");
      /* An error ocurred, just print it to stdout */
    }
  }

}

void Fork(int sockfd, int new_fd)
{
  int n;
  char buffer[256];
  bzero(buffer, 256);

  close(sockfd); // child doesn't need the listener
  if (send(new_fd, "Hello, world!", 13, 0) == -1)
  {
    perror("send");
  }

  n = read(new_fd, buffer, 255);
  if (n > 0)
  {
    printf("NOW-> %i  ::: %s", n, buffer);
  }

  close(new_fd);
  exit(0);
}
c sockets posix-select
1个回答
-1
投票

保持套接字连接打开:

使用带有“keepalive”选项的setsockopt()函数

#include <sys/socket.h>

int setsockopt(int socket, int level, int option_name,
    const void *option_value, socklen_t option_len);

SO_KEEPALIVE
Keeps connections active by enabling the periodic transmission of messages, if this is supported by the protocol. 
This option takes an int value.

Return Value

Upon successful completion, setsockopt() shall return 0. Otherwise, -1 shall be returned and errno set to indicate the error. 

这是一个例子

int on = 1;
if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0)
{ // then setsockopt failed
    perror( "setsockopt failed for SO_KEEPALIVE" );
    exit( EXIT_FAILURE );
}

这里引用:http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html关于keepalive的setsockopt()

开始引用: 》2.4.防止因网络不活动而断开连接 keepalive 的另一个有用目标是防止不活动导致通道断开。当您位于 NAT 代理或防火墙后面时,无故断开连接是一个非常常见的问题。此行为是由代理和防火墙中实现的连接跟踪程序引起的,该程序跟踪通过它们的所有连接。由于这些机器的物理限制,它们只能在内存中保留有限数量的连接。最常见和最合乎逻辑的策略是保留最新的连接并首先丢弃旧的和不活动的连接。 返回对等点 A 和 B,重新连接它们。通道打开后,等待事件发生,然后将其传达给另一个对等方。如果事件在很长一段时间后验证怎么办?我们的连接有其范围,但代理不知道。因此,当我们最终发送数据时,代理无法正确处理它,连接就会中断。 由于正常实现会在其中一个数据包到达时将该连接置于列表顶部,并在需要消除条目时选择队列中的最后一个连接,因此定期通过网络发送数据包是始终处于最佳状态的好方法。极性位置具有较小的删除风险。 ” 引用结束:

© www.soinside.com 2019 - 2024. All rights reserved.