首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >顺序服务器: accept(2)调用时的行为

顺序服务器: accept(2)调用时的行为
EN

Stack Overflow用户
提问于 2013-03-03 03:58:59
回答 2查看 489关注 0票数 0

我有一个在非并发单进程实现中具有TCP套接字的服务器。

代码语言:javascript
复制
int main(int argc, char** argv) {

    int sock_ds, acc_sock_ds, opt, client_addr_l;
    unsigned short port;
    struct sockaddr_in server_addr, client_addr;


    /*Parsing command line: port-number retrieving*/
    /*...*/

    printf("Port number retrieved (%d), server is starting ...\n", port);

    /*TCP Socket creation*/
    sock_ds = socket(AF_INET, SOCK_STREAM, 0); 
    if(sock_ds == -1){
        fprintf(stderr, "Socket creation error\n");
        exit(EXIT_FAILURE);
    }

    /*Server address binding*/
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    //use setsockopt(2) with OS_REUSEADR ???
    if(bind(sock_ds, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
        fprintf(stderr, "Address binding error\n");
        exit(EXIT_FAILURE);
    }

    /*Server with passive socket*/
    if(listen(sock_ds, SOMAXCONN) == -1){
        fprintf(stderr, "Listen call error: %s\n", strerror(errno));
        exit(EXIT_FAILURE);
    }

    printf("Server is ready. Waiting for connections.\n");

        /*Busy-waiting server*/
while(1){

    memset(&client_addr, 0, sizeof(client_addr));
    acc_sock_ds = accept(sock_ds, &client_addr, &client_addr_l);
    /*Connect error management*/
    if(acc_sock_ds == -1){
         errsv = errno;
         if(errsv == 12 || errsv == 23 ){
            /*Fatal errors ENOMEM, ENFILE*/
            fprintf(stderr, "Fatal error on accept\n");
            exit(EXIT_FAILURE);
         }
         else if(errsv == 103 || errsv == 4 || errsv == 71 || errsv == 92 
                 || errsv == 112 || errsv == 113 || errsv == 95 || errsv == 101)
             /*ECONNABORTED, EINTR, EPROTO, ENOPROTOOPT, 
              * EHOSTDOWN, EHOSTUNREACH, EOPNOTSUPP, ENETUNREACH*/
             continue;
         else if(errsv == 100 || errsv == 64){
             /* ENETDOWN - ENONET */
             /*start timeout...*/
             continue;
         }
    }
  }
}

在此测试中,我预计服务器将继续调用accept(2),同时也会出现故障。我知道有一些终端错误情况,比如EBADF。我是否应该根据errno的值提供不同的行为(进程的终止)?对于哪些值​​,服务器必须停止,而哪些值可能会继续等待?

代码已编辑。我从来没有让​​通过errno来处理错误。如果有错误或建议,请通知他们。我注意到,网络的缺失暗示了ENETDOWN - ENONET这两个条件。对于这些情况,我应该预料到超时以防止停滞吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-03-03 04:29:43

查看在MacOS X上记录的accept(2)错误代码(对于大多数兼容POSIX的系统,这些错误代码应该是一致的):

  • EBADF -程序员错误-如果原始套接字调用succeeded
  • ECONNABORTED -尝试again
  • EFAULT -程序员错误-不可能发生,除非套接字被invalid
  • EINTR -调用中断,尝试again
  • EINVAL -“socket不愿意接受连接”-我不确定这将如何发生。这可能是由于没有首先调用FD(程序员错误),尽管在某些操作系统上,这也可能是由于程序员error)
  • EMFILE -程序员错误-您耗尽了每个进程的FD,但除非您忘记关闭them
  • ENFILE -系统耗尽FDs这可能是fatal
  • ENOMEM -系统内存耗尽-这可能是fatal
  • ENOTSOCK -程序员错误-不可能发生,除非您忘记关闭listen(2) -这可能是namelen参数为负您传递了一个不是socket
  • EOPNOTSUPP的FD -程序员错误-除非您传递的套接字不是SOCK_STREAM
  • EWOULDBLOCK -程序员错误-您的套接字被配置为non-blocking

此外,Linux系统似乎还可以生成ENETDOWNEPROTOENOPROTOOPTEHOSTDOWNENONETEHOSTUNREACHEOPNOTSUPPENETUNREACH。这些是您应该循环查找的网络错误。

总而言之,您可能应该:

在调试任何其他内容时,

  • 会从Linux
  • assert()中退出ECONNABORTEDEINTR上的ENFILEEINTR程序以及上面的列表-这些运行时错误应该只会由于代码中的逻辑错误而发生,而不会因为与网络相关的事件而发生。
票数 2
EN

Stack Overflow用户

发布于 2013-03-03 20:23:34

风格:

  • 使用符号常量,而不是将它们放在注释中当意外错误时至少报告错误号
  • 处理默认/意外情况,too

顺便说一句:下面的大多数符号常量似乎并不存在。

代码语言:javascript
复制
#include <errno.h>
#include <strings.h>

 /* Busy-waiting server */
while(1){

    memset(&client_addr, 0, sizeof(client_addr));
    acc_sock_ds = accept(sock_ds, &client_addr, &client_addr_l);
    /*Connect error management*/
    if(acc_sock_ds == -1){
        switch(errsv=errno) {
            /*Fatal errors ENOMEN, ENFILE, all others*/
        default :
        case ENOMEM :
        case ENFILE :
            fprintf(stderr, "Fatal error on accept %d(%s)\n"
                , errsv, strerror(errsv)
                );
            exit(EXIT_FAILURE);
            /* normal NON-ERROR error conditions */
        case ECONNABORTED :
        case EINTR :
        case EPROTO :
        case ENOPROTOOPT :
        case EHOSTDOWN :
        case EHOSTUNREACH :
        case EOPNOTSUPP :
        case ENETUNREACH :
             continue;
        case ENETDOWN :
        case ENONET :
             /*start timeout...*/
             continue;
         }
    }
  }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15178800

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档