服务器应用程序挂起Java套接字编程
我的应用程序一直在加载(圈出光标)。这是我的密码服务器应用程序挂起Java套接字编程,java,sockets,tcp,connection,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
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();
}
}
}
我是套接字编程新手,如果我的代码有任何问题,请有人帮助我您的应用程序停止响应,因为它没有线程化。如果不使用多线程,您的应用程序将在您单击“链接”按钮时“停止”,因为调用 原因是
accept
方法的阻塞性质。直到另一个套接字连接到ServerSocket
时,该套接字将等待并保持其当前线程“挂起”。将其视为一个内部while循环,与此类似:
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();
}
}
}
}
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.
}
}
}
对此类类的调用可能如下所示:
Server.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();
}
}
}
}
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.
}
}
}
公平地说,这可能不是最好的方法,但它是我处理阻塞操作的首选方法。您应该考虑通过,并明确地看一看,因为它们是一个令人难以置信的框架来轻松处理线程池。
另外,对于JavaFX,有一个特别的方法。首先使用GUI/JFX线程运行套接字。因此,
accept()
将阻止它(用户界面将不负责,您知道)
您需要使用另一个线程运行IO/socket。但是请注意,您需要使用UI线程更改UI内容。(例如textLbl.setText(text);
如果直接从另一个线程调用,则可能会失败)
还有这一行
text=dis.toString()
是胡说八道,你们应该从客户端得到一个字符串吗?因此,请使用(推荐)来自BufferedReader
的readLine()
方法,而不是DataInputStream
。(readUTF
也可以从DataInputStream
工作)。能否详细介绍一下“我的应用程序一直在加载”以及如何调用linkAndroid()
以及在此期间是否连接了任何设备。因为乍一看一切都很好代码>根据发布的代码,您将得到一个空指针异常。我有一个名为(linkBtn)的按钮,它启动服务器并等待有人连接。按下它后,它会继续加载,最终当你点击它时,会弹出“无响应”窗口。不,我的控制台上没有任何错误。我还没有制作客户端应用程序(将在android设备上),您的UI是否在专用线程中运行?如果不是的话,这种行为的可能原因可能是因为它在建立连接之前一直在执行阻塞操作。这就是为什么我在尝试从其他线程设置标签的文本时得到NullPointerException的原因吗?我一直在试图找出如何从处理连接的线程访问控制器的标签。它不应该是空点异常,但set text op可以被忽略,或者引发另一个异常。如果得到null point ex,则必须检查变量是否正确初始化。在catch中,当您打印堆栈跟踪时,请检查导致此错误的行。修复起来很简单。继续做好工作。