如何强制服务器套接字重新接受来自客户端的请求?

发布于 2024-08-25 10:17:59 字数 1133 浏览 6 评论 0原文

对于那些不想阅读长问题的人,这里有一个简短的版本:

服务器有一个为客户端打开的套接字。服务器收到打开套接字的请求 相同的客户端 IP 和客户端端口。我希望服务器不要拒绝这样的请求,而是关闭旧套接字并打开一个新套接字。我该怎么办?


这是一个很长的(原始)问题:

我有以下情况。服务器和客户端之间已建立连接。然后外部软件(Bonjour)对我的客户端说它在本地网络中看不到服务器。那么,客户端对此不采取任何措施,原因如下:

  1. 如果 Bonjour 没有看到服务器,并不一定意味着客户端无法看到服务器。

  2. 即使客户端信任 Bonjour 并关闭套接字,也不会改善情况(“没有打开的套接字”比“有一个潜在的坏套接字”更糟糕)。

因此,如果服务器对 Bonjour 不可见,客户端将不执行任何操作。但是服务器会重新出现在 Bonjour 中,并且 Bonjour 会通知客户端这一点。在这种情况下,可能会出现以下情况:

  1. 服务器重新出现在新的 IP 地址上。因此,客户端需要打开一个新的套接字才能与服务器通信。

  2. 服务器重新出现在旧的 IP 地址上。在这种情况下,我们有两种子情况:

2.1。服务器已重新启动(关闭然后打开)。因此,它不记得旧的套接字(客户端仍在使用)。因此,客户端需要关闭旧套接字并打开一个新套接字(在相同的服务器 IP 地址和相同的服务器端口上)。

2.2.我们遇到了暂时的网络问题,服务器一直在运行。所以,旧的插座仍然可以使用。在这种情况下,客户端实际上并不需要关闭旧套接字并重新打开一个新套接字。

但为了简化我的生活,我决定在任何情况下都关闭并重新打开客户端的套接字(尽管事实上在最后描述的情况下并不真正需要它)。

但我可能对该解决方案有疑问。如果我关闭客户端的套接字,然后尝试从相同的客户端 IP 和客户端端口重新打开套接字,服务器将不会接受对新套接字的调用。服务器会认为这样的套接字已经存在。

我可以以这样的方式编写服务器,使其不拒绝此类调用吗?例如,如果它(服务器)看到客户端从相同的客户端 IP 和客户端端口发送套接字请求,则它(服务器)关闭与此客户端 IP 和客户端端口关联的可用套接字,并且比它重新打开一个新的套接字。

For those who do not want to read a long question here is a short version:

A server has an opened socket for a client. The server gets a request to open a socket from
the same client-IP and client-port. I want to fore the server not to refuse such a request but to close the old socket and open a new one. How can I do ti?


And here is a long (original) question:

I have the following situation. There is an established connection between a server and client. Then an external software (Bonjour) says to my client the it does not see the server in the local network. Well, client does nothing about that because of the following reasons:

  1. If Bonjour does not see the server it does not necessarily means that client cannot see the server.

  2. Even if the client trusts the Bonjour and close the socket it does not improve the situation ("to have no open socket" is worser that "to have a potentially bad socket").

So, client do nothing if server becomes invisible to Bonjour. But than the server re-appears in the Bonjour and Bonjour notify the client about that. In this situation the following situations are possible:

  1. The server reappears on a new IP address. So, the client needs to open a new socket to be able to communicate with the server.

  2. The server reappears on the old IP address. In this case we have two subcases:

2.1. The server was restarted (switched off and then switched on). So, it does not remember the old socket (which is still used by the client). So, client needs to close the old socket and open a new one (on the same server-IP address and the same server-port).

2.2. We had a temporal network problem and the server was running the whole time. So, the old socket is still available for the use. In this case the client does not really need to close the old socket and reopen a new one.

But to simplify my life I decide to close and reopen the socket on the client side in any case (in spite on the fact that it is not really needed in the last described situation).

But I can have problems with that solution. If I close the socket on the client side and than try to reopen a socket from the same client-IP and client-port, server will not accept the call for a new socket. The server will think that such a socket already exists.

Can I write the server in such a way, that it does not refuse such calls. For example, if it (the server) sees that a client send a request for a socket from the same client-IP and client-port, it (server) close the available socket, associated with this client-IP and client-port and than it reopens a new socket.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

め可乐爱微笑 2024-09-01 10:17:59

您无法“重新打开”服务器上的套接字。如果套接字已经存在并且客户端正在尝试重新连接,那么您应该得到一个 BindException (请参阅您之前的问题)。可能出现的情况:

  • 客户端关闭套接字
  • 服务器操作系统“注意到”套接字在客户端已死亡并关闭其端
  • 客户端在同一端口上重新连接,但使用“新”套接字

在这种情况下,您可能会认为它是“相同”的套接字,但事实并非如此。也就是说,您可能希望采用的策略是对您用于服务套接字或某种持久状态数据的任何机制进行某种映射(客户端 IP/端口的哈希),以便它可以模拟连续的先前的套接字(与 http 会话相同)。大致如下:

HashMap<Client, State> sessions = ...;

public void server(){
  ...
  while(true){
    Socket socket = server.accept();
    Client client = new Client(socket);
    State s = sessions.get(client);
    if(s == null){
      s = new State();
      sessions.put(client, s);
    }
    client.setState(s);
    service(client);
  }
  ...
}

您可以调整映射查找来定义应用程序中“会话”的含义(相同的客户端 IP、相同的客户端 IP 和客户端端口、通过线路发送的一些 sessionid 等)。

如果您只是想让客户端重新连接并强制服务器“注意到”客户端已断开连接,那么 Java 中唯一真正的方法是尝试读取/写入数据,如果它已关闭,那么它应该抛出异常。因此,正如您在其他问题中提到的,您可以在协议中添加某种 ack/nak 功能,并添加某种类型的检查,如果您认为客户端已断开连接(例如,如果您在过去 N 毫秒内没有读取任何数据) ,发送消息客户端必须在M毫秒内回显,否则假定已断开连接)。您还可以尝试 isConnected、isInputShutdown、isOutputShutdown,但我发现这些在我自己的代码中指示套接字状态是不可靠的,除非您已关闭套接字(即您在服务器上测试的套接字)。

You can't "reopen" a socket on your server. If the socket already exists and the client is trying to reconnect then you should get an BindException (see your previous question). The scenario that may be possible:

  • Client Shuts down socket
  • Server OS "notices" socket is dead on client side and shuts its side down
  • Client reconnects on the same port, but with a "new" socket

In this case you may consider it be the "same" socket, but it really isn't. That said a strategy you may wish to adopt is to have some sort of map (hash of client IP/port) to whatever mechanism you are using to service the socket or some kind of persistent state data, so that it can simulate a continuation of a previous socket (in the same vein as http sessioning). Something along the lines of:

HashMap<Client, State> sessions = ...;

public void server(){
  ...
  while(true){
    Socket socket = server.accept();
    Client client = new Client(socket);
    State s = sessions.get(client);
    if(s == null){
      s = new State();
      sessions.put(client, s);
    }
    client.setState(s);
    service(client);
  }
  ...
}

and you can adjust the map lookup to define what a "session" means within your application (same client IP, same client IP & client port, some sessionid sent over the wire, etc).

If you are just trying to make it possible for the client to reconnect and force the server to "notice" the client is disconnected, the only real way in Java is to try and read/write data, and if it has been shutdown then it should throw an exception. Therefore as was mentioned in your other question you could add some kind of ack/nak feature to your protocol and add some type of check if you believe the client is disconnected (for example if you haven't read any data in the last N milliseconds, send a message the client must echo within M milliseconds, otherwise it is assumed to be disconnected). You can also try isConnected, isInputShutdown, isOutputShutdown, but I have found those to be unreliable in my own code to indicate the socket state, unless you have closed the socket (i.e. the one you are testing on the server).

非要怀念 2024-09-01 10:17:59

你描述的情况是不可能的。您无法从与现有连接相同的远程 IP:端口获取新的连接请求。客户不会允许这种情况发生。

The situation you describe is impossible. You can't get a new connect request from the same remote IP:port as an existing connection. The client will not permit it to occur.

旧人 2024-09-01 10:17:59

根据评论:

您不能以关闭仍认为已连接的套接字并自动接受新连接的方式编写服务器,因为应用程序代码对 TCP 堆栈没有这种控制权,也没有重新打开连接的方法。

客户端重新启动之间端口号相同的可能性非常小。

但是,如果发生这种情况,服务器会注意到您正在尝试设置已连接的套接字,并拒绝您的新连接。在这种情况下,除了关闭套接字、创建一个新套接字并尝试再次连接之外,您的客户端无能为力 - 并且将选择另一个随机端口。

附加说明,您的服务器应该采取某种形式的操作来检测并关闭死套接字,如果您的服务器所做的只是读取传入数据,那么“死”套接字将永远不会被删除。
关闭,因为它们永远不会被检测为死亡。(启用 tcp keepalive 是防止死套接字持续数月的一种廉价措施,尽管默认情况下需要几个小时才能检测到它们。)

Based on the comments:

You cannot write the server in a way that it will close a socket it still thinks is connected and automatically accept the new connection, as application code does not have that kind of control over the TCP stack, nor is there a way to reopen a connection.

The chance of the port numbers being the same between your client restarts is very small.

But still, if that happens, the server will note that that you're trying to set up an already connected socket, and refuse your new connection. There's not much else your client can do in this case besides close your socket, create a new one and try to connect again - and another random port will be selected.

additional note, your server should take some form of action to detect and close dead sockets, if all your server does is read incoming data, the "dead" sockets will never be
closed as they will never be detected as dead.(enabling tcp keepalive is one cheap measure to take against dead sockets staying up for months, though it will take a couple of hours to detect them as such by default.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文