【问题标题】:close tcp socket when the program was stopped by kill command当程序被 kill 命令停止时关闭 tcp 套接字
【发布时间】:2015-04-01 13:57:00
【问题描述】:

我开发了一个包含小型 http 服务器的应用程序。

我的应用程序在启动时启动。如果应用程序正常停止(etc/init.d/myappli stop),套接字将被关闭

close (socket_desc); 

但如果我用kill -9 杀死它,套接字将不会关闭

http 服务器代码:

void http_server_init(void)
{
    struct sockaddr_in server;
    int cr_port;

    for(;;) {
        cr_port = conf.port;
        int i = (DEFAULT_PORT == cr_port)? 1 : 0;
        //Create socket
        cr_socket_desc = socket(AF_INET , SOCK_STREAM , 0);
        if (cr_socket_desc == -1)
        {
            LOG (ERROR,"Could not open server socket, Error no is : %d, Error description is : %s", errno, strerror(errno));
            sleep(1);
            continue;
        }

        /* enable SO_REUSEADDR */
        int reusaddr = 1;
        if (setsockopt(cr_socket_desc, SOL_SOCKET, SO_REUSEADDR, &reusaddr, sizeof(int)) < 0) {
            LOG (WARNING,"setsockopt(SO_REUSEADDR) failed");
        }

        //Prepare the sockaddr_in structure
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = INADDR_ANY;
        for(;;i++) {
            server.sin_port = htons(cr_port);
            //Bind
            if( bind(cr_socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
            {
                //print the error message
                LOG (ERROR,"Could not bind server socket on the port %d, Error no is : %d, Error description is : %s", cr_port, errno, strerror(errno));
                cr_port = DEFAULT_PORT + i;
                LOG (INFO,"Trying to use another port: %d", cr_port);
                continue;
            }
            break;
        }
        break;
    }
    LOG (INFO,"server initiated with the port: %d", cr_port);
}

问题:

1) 如果程序被杀,如何关闭socket?

2)在这种情况下应该使用什么类型的套接字来避免套接字不会被另一个使用tcp套接字的进程使用?

【问题讨论】:

  • 当你的进程退出时,所有文件描述符都会被操作系统关闭,所以不用担心。
  • 由于 SIGKILL (-9) 无法处理,close() 应该由操作系统自动完成。你有这方面的问题吗?
  • 什么观察让你觉得“套接字不会被关闭”?
  • 因为端口被另一个进程占用了!!!!
  • 如果您正在关闭进程并立即尝试重新启动它,则连接可能只是处于TIME_WAIT 状态一段时间,这是正常的。

标签: c sockets tcpsocket


【解决方案1】:

如果你用kill -9 杀死一个程序,端口被关闭,不是由程序关闭,而是由操作系统关闭。它被关闭的事实正是使它可以被另一个进程接管的原因。

端口不是为特定程序“保留”的。程序终止后唯一保留的端口是如果您设置SO_REUSEADDR,在这种情况下,它会保留(从内存中)2 个TIME_WAIT 周期。但是你已经在你设置SO_REUSEADDR的cmets中告诉我们。这意味着“使该端口可用于下一个尝试侦听它的程序”。它不区分该程序是相同程序还是不同程序。

我想你认为SO_REUSEADDR 的意思是'这个程序可能想重用端口,所以不要把它给其他人'。这绝对是不是SO_REUSEADDR 所做的。 SO_REUSEADDR(广义地说,无论如何在 Unix 上)在程序死后立即释放端口供任何程序使用到操作系统,而不是等待一段时间。在 MS 上,它(有点奇怪)用于绑定到已经在使用的端口。有关更多信息,请参阅Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems? - 但是请注意,在 no 操作系统上,这是否意味着我猜你认为的意思。

【讨论】:

  • AKA '不要在同一个监听端口上使用两台服务器'。有点明显,真的:)
  • 真的很奇怪,如果我的程序被kill -9停止了,另一个服务怎么会占用我程序的socket的端口
  • 当您的进程终止时,另一个服务这样做有什么奇怪的?奇怪的是,如果它在您的进程运行时这样做。
  • @Anis_Stack 您的程序已停止。它不再使用该端口。因此另一个程序可以使用它。就这么简单。我添加了另一段来解释。
【解决方案2】:

您的问题是旧套接字在释放前不久将处于TIME_WAIT 状态。 如果您想减少在TIME_WAIT 状态中花费的时间,您可以减少逗留时间。请注意,过度减少它会带来风险。

您可以使用setsockopt(2) 更改套接字的延迟时间。

相关链接:

The ultimate SO_LINGER page

TCP option SO_LINGER (zero)

【讨论】:

  • 我认为这是不对的。 OP 在他设置的 cmets 中告诉我们SO_REUSEADDR,这意味着它应该可以立即重复使用。此外,他似乎并没有抱怨套接字不能被重用;相反,他抱怨它可以被重用(由其他程序)。所以他的问题不可能是socket卡在TIME_WAIT。我同意你已经很好地回答了关于这个主题的最常见问题,但显然不是这个问题。
  • 公平地说,从问题或 cmets 中根本不清楚 OP 如何知道套接字正在被不同的程序而不是同一个程序重用,或者他/她是否对了。对我来说,在杀死他的进程和重新启动它之间的时间内,让另一个进程潜伏并跳入窃取它似乎不太可能。这个问题措辞不佳,实际上根本没有要求解释暗示但未描述的行为 - 只是“如果程序被杀死,如何关闭套接字?”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-09-14
  • 2011-01-26
  • 1970-01-01
  • 2012-02-08
  • 2015-12-07
  • 2016-06-03
  • 2015-10-30
相关资源
最近更新 更多