由于连接突发而导致套接字连接被拒绝

时间:2016-09-21 20:42:55

标签: c sockets parallel-processing synchronization

我正在使用套接字来同步多个远程进程。

这个想法是一个进程创建了一个管理服务器端的pthread,就像那样:

void *listener(void * in) {
  int sockfd;
  socklen_t clilen;
  struct sockaddr_in serv_addr, cli_addr;
  int n = *((int *) in);

  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd < 0)
      error("ERROR opening socket");

  int option = 1;
  setsockopt(sockfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), (char*) &option, sizeof (option));
  bzero((char *) &serv_addr, sizeof (serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_addr.s_addr = INADDR_ANY;
  serv_addr.sin_port = htons(PORT);

  if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
      error("ERROR on binding");

  if (listen(sockfd, n) < 0)
      error("ERROR when listening");

  clilen = sizeof (cli_addr);
  int cnt = 0;
  while (cnt < n) {
      int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
      if (newsockfd < 0) {
          error("ERROR on accept");
      }
      cnt++;
  }
  close(sockfd);
  return 0;
}

同时,其他进程将执行:

int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
  error("ERROR opening socket");

server = gethostbyname(_managementHost); //managementHost);
if (server == NULL)
  error("ERROR, no such host\n");

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

if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0)
  error("ERROR connection");

close(sockfd);

现在,我遇到的问题是当我有很多进程试图同时连接到服务器时,其中一些进程正在抛出连接拒绝错误。

我想这是因为接受可能还没准备好......事实上,我已经读过它可能会发生,但我没有找到我的具体案例。

有人能说清楚这件事吗?

我遇到的一个可能的解决方案是为每个接受创建一个线程,但我宁愿避免使用它。

谢谢。

编辑:更正了服务器中套接字的双重初始化。感谢@Remy Lebeau。

2 个答案:

答案 0 :(得分:1)

  

现在,我遇到的问题是当我有很多进程试图同时连接到服务器时,其中一些会抛出连接拒绝错误。

侦听TCP套接字具有待处理连接的积压。 listen()的第二个参数指定在接受之前允许在积压队列中连接的连接数。如果新客户端在待办事项已满时尝试连接,则拒绝客户端。客户端或服务器无法做到这一点。客户有责任检测错误并在以后重新连接。

您的listener()正在接受客户端,直到达到指定数量的连接,但您也使用相同的号码作为侦听积压队列大小。活动连接数和挂起连接数是两回事。如果您希望许多客户端同时连接,则需要大量的积压大小以避免拒绝错误。但是积压的大小应该与您期望的流量成比例。如果您有1000个客户端,但它们一次只能连接20个,那么您可以将待办事项设置为25,而不是1000.

您的listener()还有一些其他逻辑错误。它正在调用socket()两次并将两个套接字保存到同一个sockfd变量,因此它泄漏了第一个套接字。您需要删除对socket()setsockopt()之前的那个)的第二次调用。您还泄漏了accept()返回的套接字。在使用它之后,你需要close()一个被接受的套接字。

答案 1 :(得分:0)

通过调用fork为每个客户端生成一个子项,让您的服务器并发。最简单的方法,IMO。避免线程并停止连接拒绝错误。

编辑:你也可以考虑预先分叉你的服务器。你必须研究如何处理锁定接受(如果你完全锁定)。