gpt4 book ai didi

java - 应用程序卡在 serverSocket.accept() 并提供已在第二次调用线程时使用的绑定(bind)异常地址

转载 作者:可可西里 更新时间:2023-11-01 02:34:29 58 4
gpt4 key购买 nike

我为套接字通信构建的应用程序有两个问题,首先我将尝试解释该应用程序的功能,然后我将详细介绍这两个问题。首先,我单击一个按钮,启动一个线程,该线程通过 UDP 套接字发送多播消息“组地址”。一旦任何设备收到消息,它们将通过 TCP 套接字发送响应,而我的设备将充当发送响应的设备的服务器。所以在调试之后我发现了第一个问题是 clientSocket = serverSocket.accept(); 有时会卡住,应用程序会阻止所有内容并继续执行它,这可能会发生,因为 udp 信息可能永远不会到达在目的地,这意味着我创建的 tcp 服务器没有客户端。

第一个问题:有什么方法可以使serverSocket.accept(); 非阻塞或设置超时?我试过 serverSocket.setTimeSoOut() 方法,但没有用。也许这个问题来自 UDP 消息以外的其他原因?

第二个问题是,如果我按下调用线程的按钮两次,它将抛出一个已经在使用中的 BindException 地址:这是由于 serverSocket.bind(new InetSocketAddress(4125)) 的重新执行而发生的;。有什么办法可以解决/避免这种情况吗?

以下是我正在使用的线程:这个在我按下按钮后被调用:

 private class ChatClientThread extends Thread {

DatagramSocket socket;
String sentence;
String modifiedSentence;
BufferedReader inFromUser;

DataOutputStream outToServer;
BufferedReader inFromServer;
Socket clientSocket;
ServerSocket serverSocket;
@Override
public void run() {
/*Socket socket = null;
DataOutputStream dataOutputStream = null;
DataInputStream dataInputStream=null;*/
clientSocket=null;


try {
String data="NewTask_"+EmpPhoneNumber;

serverSocket=new ServerSocket();
serverSocket.setReuseAddress(true);
serverSocket.bind(new InetSocketAddress(4125));
socket = new DatagramSocket(52276);
socket.setBroadcast(true);
InetAddress group = InetAddress.getByName(
"224.0.1.2");
DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(),
group, 52276);

socket.send(packet);

while(true){
clientSocket = serverSocket.accept();

ConnectThread ct=new ConnectThread(clientSocket);
ct.start();
}

} catch (UnknownHostException e) {
e.printStackTrace();
final String eString = e.toString();
TicketDetails.this.runOnUiThread(new Runnable() {

@Override
public void run() {
Toast.makeText(TicketDetails.this, eString, Toast.LENGTH_LONG).show();
}

});
} catch (IOException e) {
e.printStackTrace();
final String eString = e.toString();
TicketDetails.this.runOnUiThread(new Runnable() {

@Override
public void run() {
Toast.makeText(TicketDetails.this, eString, Toast.LENGTH_LONG).show();
}

});
} finally {






TicketDetails.this.runOnUiThread(new Runnable() {

@Override
public void run() {

}

});
}

}


}

如您所见,这是从上面的线程调用的:

private class ConnectThread extends Thread {

Socket socket;
String sentence;
String modifiedSentence;
BufferedReader inFromUser;

DataOutputStream outToServer;
BufferedReader inFromServer;
ConnectThread(Socket socket){

this.socket= socket;

}

@Override
public void run() {
DataInputStream dataInputStream = null;
DataOutputStream dataOutputStream = null;
Socket socket2 = null;
DataOutputStream dataOutputStream2= null;
DataInputStream dataInputStream2=null;

try {
while(true){


inFromUser = new BufferedReader( new InputStreamReader(System.in));
outToServer = new DataOutputStream(socket.getOutputStream());
inFromServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
sentence = inFromUser.readLine();


modifiedSentence = inFromServer.readLine();
socket2 = new Socket(socket.getInetAddress().getHostAddress(), 4125);
dataOutputStream2 = new DataOutputStream(
socket2.getOutputStream());

String[] parts = modifiedSentence.split("_");
String partGive = parts[0].substring(4); // 004
String partEmpId = parts[1];
if(partGive.equals("GiveMeATask")&&Integer.parseInt(partEmpId)==empId){

dataOutputStream2.writeUTF(" "+"SolveProblemOrder_2");
dataOutputStream2.flush();
}



System.out.println("FROM SERVER: " + modifiedSentence);


if(modifiedSentence!=null) break;}

outToServer.close();
inFromServer.close();


} catch (IOException e) {
e.printStackTrace();
} finally {
if (dataInputStream != null) {
try {
dataInputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

if (dataOutputStream != null) {
try {
dataOutputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


}

}



}

最佳答案

这是两个非常常见的问题。我将以相反的顺序回答这两个问题。

  1. 您所说的按钮是创建一个 ServerSocket 并将其绑定(bind)到特定端口。在你的情况下,端口是 4125。从你的代码来看,你似乎没有在任何地方关闭那个 serversocket。当您第二次单击该按钮时,ServerSocket 的第二个实例会尝试绑定(bind)到同一个端口 - 但该端口仍由第一个 ServerSocket 使用。在这种情况下,您会得到一个绑定(bind)异常。一个端口不能被多个 ServerSocket 使用。解决方案是在使用 serverSocket.close();

    创建新的之前关闭现有的 ServerSocket
  2. 如果您阅读 the documentation ,它清楚地说明了 ServerSocket.accept() 的作用:“[...] 该方法会阻塞,直到建立连接。”这就是您描述的“卡住”。执行该代码的线程被置于等待位置并仅在建立连接时继续,然后返回该新连接。经典的方法是启动一个等待传入连接的新线程,以便您的主线程继续执行并且您的整个应用程序不会“卡住”。另一种方法是一个非阻塞框架,它封装了所有的开销,远离你,其中之一是 Apache MINA .

我强烈建议研究处理基本客户端/服务器行为的小型示例项目,因为您很可能会在这里处理线程。

关于java - 应用程序卡在 serverSocket.accept() 并提供已在第二次调用线程时使用的绑定(bind)异常地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30192685/

58 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com