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

时间:2010-03-17 11:13:18

标签: java networking sockets

对于那些不想阅读长篇问题的人来说,这是一个简短的版本:

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


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

我有以下情况。服务器和客户端之间建立了连接。然后外部软件(Bonjour)告诉我的客户端它没有看到本地网络中的服务器。好吧,客户端没有做任何事情,原因如下:

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

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

  3. 因此,如果服务器对Bonjour不可见,客户端什么都不做。但是,服务器重新出现在Bonjour和Bonjour中,通知客户端。在这种情况下,可能出现以下情况:

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

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

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

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

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

      但是我可以解决这个问题。如果我在客户端关闭套接字而不是尝试从同一客户端-IP和客户端端口重新打开套接字,则服务器将不接受对新套接字的调用。服务器会认为这样的套接字已经存在。

      我能否以这样的方式编写服务器,它不会拒绝这样的调用。例如,如果它(服务器)发现客户端从同一客户端IP和客户端端口发送套接字请求,则它(服务器)关闭与此客户端IP和客户端端口关联的可用套接字,而不是重新打开一个新的插座。

3 个答案:

答案 0 :(得分:0)

您无法在服务器上“重新打开”套接字。如果套接字已经存在且客户端正在尝试重新连接,那么您应该获得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和客户端端口,通过网络发送的某些会话ID等)。

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

答案 1 :(得分:0)

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

答案 2 :(得分:-1)

根据评论:

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

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

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

另外请注意,您的服务器应采取某种形式的操作来检测和关闭死套接字,如果您的所有服务器都读取传入数据,那么“死”套接字将永远不会 关闭,因为它们永远不会被检测为死亡。(启用tcp keepalive是一种廉价的措施,可以防止死机插座停留数月,但默认情况下需要花费几个小时来检测它们。)