TCP 套接字关闭但未被进程检测到

Posted

技术标签:

【中文标题】TCP 套接字关闭但未被进程检测到【英文标题】:TCP socket closing but not detected by process 【发布时间】:2015-09-14 06:35:40 【问题描述】:

我有一个允许连接的服务器,然后根据它接收到的消息,服务器应该做一些事情(目前尚未实现)但是如果套接字关闭,服务器也应该提醒我它没有不。

sloop(Listen)->
    ok, Socket = gen_tcp:accept(Listen),
    io:format("Someone connected"),
    master ! add,Socket,
    io:format("Point A reached"),
    spawn(fun() -> sloop(Listen) end),
    io:format("Point B reached"),
    receive
        tcp, Socket, Bin ->
             case read(Bin) of
                    join,Channel -> 
                                tracker ! self(),get,Socket,
                                receive 
                                    void -> 
                                        master ! delete, Socket,
                                        A = lists:dropwhile(fun(A) -> A /= Channel end, registered()),
                                        case A of
                                            [H|_] -> H ! add,Socket;
                                            _ -> register(Channel,spawn(fun() -> listenerSocket([]) end))
                                        end,
                                    Channel ! add, Socket,
                                    tracker ! insert,Socket, Channel;
                                    ok, Value -> 
                                        Value ! delete,Socket,
                                        tracker ! delete,Socket,
                                        A = lists:dropwhile(fun(A) -> A /= Channel end, registered()),
                                        case A of
                                            [H|_] -> H ! add,Socket;
                                            _ -> register(Channel,spawn(fun() -> listenerSocket([]) end))
                                        end,
                                    Channel ! add, Socket,
                                    tracker ! insert,Socket, Channel;
                     message, Msg ->  
                                tracker ! self(),get,Socket,
                                receive 
                                    ok, Value -> Value ! broadcast, Msg
                                end
                end;
        tcp_closed, Socket -> io:format("Someone disconnected")
    end
end.

每当我打开一个套接字并将其指向 localhost:2266 时,shell 就会打印 "Someone connected" 、 "Point A reached" 、 "Point B reached" 但是每当我使用 tcp_gen:close/1 关闭套接字时,服务器不会打印“有人断开连接”。

【问题讨论】:

原子mastertracker 是变量吗? 已注册的进程 【参考方案1】:

修复代码的格式可能会有所帮助,因为这会显示您的 tcp_closed, Socket 模式匹配是 case 子句,而不是 receive 子句。我认为您打算将其作为最外层receive 的子句。

注意sloop/1 函数不是递归的,这意味着它最外层的receive 只处理一条消息,处理该消息,然后返回。也许您有其他代码没有显示重复调用sloop/1,但无论哪种方式,您都需要通过sloop/1 进行某种循环,同时将您的tcp_closed, Socket 模式匹配移动到最外面的receive,以允许您的应用程序可以正确处理多条消息。

【讨论】:

我很抱歉,但我根本无法发现。 tcp_closed, Socket 后面有两端。一个用于接收,一个用于功能。如果它是case 的子句,肯定会有另一个end?也许我在这里看不太清楚。是的。我确实有一些东西可以让这个过程保持活力。 普通函数没有end。最后的end 匹配最外面的receive,它上面的匹配case,而tcp_closed, Socket 正上方的end 匹配紧随join,Channel 之后开始的receive 啊...为什么我会认为函数有终点。谢谢【参考方案2】:

您需要递归调用侦听器函数。如所写,监听函数将在第一条消息后终止,因此不会监听gen_tcp:close 消息。处理成功后,只需要重新进入循环即可。

sloop(Listen)->
    ok, Socket = gen_tcp:accept(Listen),
    io:format("Someone connected"),
    master ! add,Socket, % <-- not sure what this does
    io:format("Point A reached"),
    spawn(fun() -> sloop(Listen) end),
    io:format("Point B reached").

loop_internal(Socket) ->
    inet:setopts(Socket,[active,once]),
    receive
        tcp, Socket, Bin -> 
            do_your_stuff(Bin),
            %% your stuff removed for brevity
            loop_internal(Socket);
        tcp_closed, Socket -> io:format("Someone disconnected")
    end
end.

【讨论】:

以上是关于TCP 套接字关闭但未被进程检测到的主要内容,如果未能解决你的问题,请参考以下文章

TCP套接字:检测对等方是不是在发送前关闭? (Linux)

如何检测 Windows 中打开的套接字?

libevent 如何检测到套接字已关闭

close函数

c++ 服务器在客户端终止连接进程后不关闭 TCP 套接字连接

close函数