【问题标题】:Connect to remote port(Server) from thread in polling从轮询线程连接到远程端口(服务器)
【发布时间】:2014-01-24 18:00:47
【问题描述】:

我想从线程连接到远程服务器并继续发送字符串。如果连接被拒绝,线程应该继续轮询端口,直到服务器再次启动。我该如何处理这个异常并保持我的线程不会崩溃?服务器可能很长时间没有启动,但线程应该无限期地运行。

public void SendMessage(String message){
    try {
        socket = new Socket(actuatorAddress, destPort.get());
        outToServer = socket.getOutputStream();
        out = new DataOutputStream(outToServer);
        out.flush();
        out.write(message.getBytes());
    } catch (IOException ex) {
        System.out.println(ex.getMessage());
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

我更改了部分代码,如下所示。第一次调用 Connect 函数,随后通过线程调用 Send Message 函数。添加到重新连接的延迟有助于减少由于连接到非现有服务器而重复出现的时间延迟。还是觉得基本问题可能有更好的解决方案。

public boolean ConnectToActuator() {
    try {
        if(actuatorAddress.isReachable(2000)){
            socket = new Socket();
            socket.setPerformancePreferences(1, 2, 0);
            socket.setTcpNoDelay(false);
            socket.setSendBufferSize(32);
            socket.connect(new InetSocketAddress(actuatorAddress, destPort.get()));
            outToServer = socket.getOutputStream();
            out = new DataOutputStream(outToServer);
            connected = true;
            disconnectedTimeout = 0;
        }
    }catch (ConnectException e) {
        // TODO Auto-generated catch block
        System.out.println(e.getMessage());
    }catch (IOException ex) {
        connected = false;
        System.out.println(ex.getMessage());
    }
    return connected;
}

public boolean SendToActuator(String message) {
    if(connected == false){ //socket.isOutputShutdown()
        disconnectedTimeout++;
        if(disconnectedTimeout>20){
            disconnectedTimeout = 0;
            ConnectToActuator();
        } else {
            return connected;
        }
    }
    try {
        out.flush();
        out.writeBytes(message);
        disconnectedTimeout = 0;
        connected = true;
    } catch (UnknownHostException uhe) {
        connected = false;
        System.out.println(uhe.getMessage());
    } catch (IOException ioe) {
        connected = false;
        System.out.println(ioe.getMessage());
    }
    return connected;
}

【问题讨论】:

  • 以分钟为单位的“长时间”是什么意思?另外,您的代码的目标是什么:您是在尝试测试服务是否启动,或者即使您不知道服务何时可用,也可以 100% 确保最终会发送消息?您是否关心某些消息是否会丢失,只要其中一些消息偶尔通过?还是您需要确保他们都收到了?
  • 目标是网络中连接的大约 10 台服务器从该线程读取消息。服务器可能会断开几分钟甚至几小时,或者可能会从网络中取出。但我仍然希望任务继续运行并向连接的其他服务器发送消息。消息丢失不是问题。
  • 基本上我想处理连接被拒绝的异常。或者,如果我可以在创建套接字之前检查连接是否会被拒绝,那就更好了。
  • 所以我们的想法是尝试连接到所有服务器,如果都没有,您可以丢弃消息吗?
  • 是的。我添加了 catch "ConnectException" 来处理这个异常,但它导致向连接的服务器发送消息时出现时间延迟。

标签: java sockets exception-handling thread-safety serversocket


【解决方案1】:

鉴于 cmets 中的以下约束:

  • 尝试将消息发送到 10 个服务器之一。
  • 如果没有服务器可用于接收消息,则丢弃该消息。

你真正想做的是:

  1. 遍历服务器地址列表
  2. 尝试向每个人发送消息
  3. 成功后立即跳出循环
  4. 捕获连接失败的任何错误并尝试下一个服务器

这是一个将贯穿该场景的示例类。

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;

public class MessageSender {
  private static final Integer destPort = 1234;

  private static final String[] serverAddresses = {
    "address1",
    "address2",
    "address3" // Etc....
  };

  public Boolean SendMessage(String message) {
    Boolean messageSentSuccessfully = false;
    for (String addy : serverAddresses) {
      messageSentSuccessfully = SendMessageToServer(addy, message);
      if (messageSentSuccessfully) {
        break;
      }
    }
    return messageSentSuccessfully;
  }

  private Boolean SendMessageToServer(String serverAddress, String message) {
    Boolean messageSent = false;
    try {
      Socket dataSocket = new Socket(serverAddress, destPort);
      OutputStream outToServer = dataSocket.getOutputStream();
      DataOutputStream out = new DataOutputStream(outToServer);
      out.write(message.getBytes());
      out.flush();
      messageSent = true;
    } catch (Exception e) {
      System.out.println(e);
    }
    return messageSent;
  }
}

希望对您有所帮助。

【讨论】:

  • 谢谢 TreyE。我尝试使用 InetSocketAddress(actuatorAddress, destPort.get()).getAddress().isReachable(timeout) 检查远程服务器是否可用,但这仅检查远程 IP 是否可访问,而不是特定端口是否可访问.
  • 问题是,您并不真正关心服务器是否可用,您只关心是否可以发送消息。所以你不妨尝试发送消息。
【解决方案2】:

伪:

while(true){
  if(connect()) DoClientConnectedStuff();
  sleep(reconnectTimeout);
};

【讨论】:

    【解决方案3】:

    请尝试以下更改。如果您的连接拒绝,它将等待 2 秒(2000 毫秒),然后再次尝试连接服务器。如果连接成功,它将获取输出流,在 while 循环中写入数据并刷新数据。

    public void createSocketConnection() throws IOException
    {     
        socket = new Socket(actuatorAddress, destPort.get());
        if(socket!=null)
            {
              outToServer = socket.getOutputStream();
              out = new DataOutputStream(outToServer);
            }
    
    }
    
    public void SendMessage(String message){
        boolean isRunning=false;
        try 
        {
            createSocketConnection();
            isRunning=true;
            while(isRunning)
            {
              out.write(message.getBytes());
              out.flush();
           }
        } catch (java.net.ConnectException conExcp) {
            System.out.println(ex.getMessage());
            try{
              Thread.sleep(2000);
            }catch(Exception ee){}
        } 
        catch (IOException ex) {
            System.out.println(ex.getMessage());
    
        } 
    }
    

    【讨论】:

    • 'socket' 在您正在测试它的品脱时不可能为空。你没有花费插座。此代码不会重试任何内容。 -1
    猜你喜欢
    • 1970-01-01
    • 2018-09-17
    • 1970-01-01
    • 2014-02-06
    • 1970-01-01
    • 2018-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多