服务器应用程序挂起Java套接字编程

时间:2018-05-30 04:44:13

标签: java sockets tcp connection

我的应用程序继续加载(圆圈光标)。这是我的代码

public class ControllerW {

@FXML
private Label statusLbl, timeLbl, textLbl;
@FXML
private Button exitBtn, linkBtn;

private ServerSocket serverSckt;
private Socket clientSckt;
DataInputStream dis;
String text;

@FXML
private void exit() {
    System.exit(0);
}

@FXML
private void linkAndroid() {
    try {
        serverSckt = new ServerSocket(5678);
        statusLbl.setText("Server started");
        clientSckt = serverSckt.accept();
        statusLbl.setText("client connected successfully");
        dis = new DataInputStream(clientSckt.getInputStream());
        text = dis.toString();
        textLbl.setText(text);
    } catch (Exception e) {
        statusLbl.setText("No connection on port 5678");
        e.printStackTrace();
    }
}

}

我是socket编程的新手,如果我的代码有任何问题,有人可以帮助我吗

2 个答案:

答案 0 :(得分:1)

您的应用程序停止响应,因为它没有线程化。如果没有多线程,您的应用程序将在您点击“链接”按钮时“停止”,因为拨打ServerSocket#accept

原因是accept方法的阻止特性。直到另一个套接字连接,ServerSocket正在等待并保持当前线程“暂停”。可以把它想象成一个与此类似的内在循环:

while(!isConnected())
{
    // check if there is a new request
}

想象一下,没有客户会连接。这个循环怎么会停止?从不。

可能的解决方法是线程整个UI部分或“数据模型”部分。

我首选的方法是创建一个只处理ServerSocket#accept方法的自定义类,并将传入的连接委托给另一个负责其余部分的线程。我这样做是为了随时保持我的服务器可访问,这可能不是解决问题的最佳方法。

这就是我的帮助程序类通常的样子:

<强> ClientAccepter.java:

public class ClientAccepter
    implements Runnable
{
  // the ServerSocket
  private final ServerSocket server;
  // ExecutorServices ease the pain of threading your application quite a lot
  private final ExecutorService es = Executors.newCachedThreadPool();

  private boolean isAlive = true;

  public ClientAccepter( ServerSocket server )
  {
    this.server = server;
  }

  @Override
  public void run()
  {
    //This is where you specify your desired behaviour.
    //Example:
    while ( isAlive )
    {
      try
      {
        es.execute( new ClientHandler( server.accept() ) );
      }
      catch ( IOException e )
      {
        e.printStackTrace();
      }
    }
  }
}

对这样一个类的调用可能如下所示:

<强> Server.java:

public class Server
{
  //ExecutorServices are the best and easy to use.
  private static ExecutorService serverThreader = Executors.newSingleThreadExecutor();

  public static void main( String[] args )
  {
    try
    {
      serverThreader.execute( new ClientAccepter( new ServerSocket( 8080 ) ) );
    }
    catch ( IOException e )
    {
      e.printStackTrace();
     //further exception handling.
    }
  }
}

公平地说,这可能不是最好的方法,但它是我处理阻止操作的首选方式。您应该考虑使用orcale concurrency tutorial并明确地查看ExecutorServices,因为它们是一个非常容易处理线程池的框架。

特别是对于JavaFX,有一个concurrency tutorial

答案 1 :(得分:0)

首先使用GUI / JFX线程运行套接字。所以accept()会阻止它(用户界面不负责任,你知道的数据圈)。

您需要使用另一个线程运行IO /套接字。但要注意,您需要使用UI线程更改UI内容。 (例如,textLbl.setText(text);如果从另一个线程直接调用则可能失败)

此行text = dis.toString();也是无意义的,你应该从客户端发送一个字符串?因此,请使用readLine()中的(推荐)BufferedReader方法,而不是DataInputStream。 (readUTF也可能来自DataInputStream)。