2016-09-21 73 views
0

我正在使用套接字来同步多个远程进程。由于连接突发而拒绝套接字连接

的想法是,一个进程创建用于管理服务器端的并行线程,就像这样:

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。

+0

我不认为我理解你正在尝试做的事情。接受连接然后泄漏它们应该完成什么?这些如何产生任何同步?或者是否删除了一些能够提供同步和非资源泄漏目标的重要位? –

+0

这个想法是,第一个进程将在'pthread_join'中等待,直到其他进程到达给定的点。我只使用套接字来同步它们,我对传递过程不感兴趣。 – siserte

回答

1

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

侦听的TCP套接字有未完成连接的积压。 listen()的第二个参数指定在被接受之前允许多少个连接在积压队列中。如果新客户端在积压已满时尝试连接,客户端将被拒绝。客户端或服务器无法做到这一点。检测错误并在稍后重新连接是客户的责任。

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

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

+0

因此,即使一个进程连接并且'accept()'还没有被发布,客户端连接仍然会在积压中,对吧? 关于错误,你是对的,我有太多'socket()'调用。然而,我不能在accept()之后关闭套接字,因为我只打开了一个套接字(它只是一个执行“listener()”的线程。是否应该为每个accept()都创建一个线程?谢谢。 – siserte

+0

@SergioIserte是的,一个连接保留在积压中,直到被accept()'删除。如果你打算一次服务多个客户,你将不得不为每个被接受的客户创建一个新的线程/进程'accept()'本身),或者在一个线程中复用多个客户端(比如使套接字非阻塞,然后使用'select()'/'epoll()'来管理它们),所以你可以回到'accept()'regular。 –

+0

对不起,我不确定你的意思是什么_accepted client_。我所指的是创建'n'线程,每个线程调用'accept()'。你有什么意思?谢谢 – siserte

0

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

编辑:你也可以看看预分叉你的服务器。你必须研究如何处理锁定周围的接受,尽管(如果你锁定的话)。

+0

我宁愿避免分叉新进程,如果可能的话... – siserte