我在为套接字通信构建的应用程序中遇到两个问题,首先我将尝试解释应用程序的功能,然后我将详细介绍这两个问题。
首先,我点击一个按钮,它启动一个线程,通过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();
}
}
}
}
}
答案 0 :(得分:1)
这是两个非常常见的问题。我会以相反的顺序回答这两个问题。
您正在谈论的按钮是创建ServerSocket并将其绑定到特定端口。在您的情况下,端口是4125.从查看您的代码,您似乎无法在任何地方关闭该serversocket。当您再次单击该按钮时,ServerSocket的第二个实例尝试绑定到同一个端口 - 但该端口仍由第一个ServerSocket使用。在这种情况下,您将获得绑定异常。一个端口不能被多个ServerSocket使用。解决方案是在使用serverSocket.close();
如果您阅读the documentation,它会清楚地说明ServerSocket.accept()的作用:" [...]方法会阻塞,直到建立连接。"这就是"卡住了#34;你所描述的。执行该代码的线程被置于等待位置,并且仅在建立连接时继续,然后返回该新连接。经典的方法是启动一个等待传入连接的新线程,以便主线程继续执行,整个应用程序不会“冻结”#34;。另一种方法是一个非阻塞框架,它封装了所有远离你的开销,其中一个是Apache MINA。
我强烈建议您查看处理基本客户端/服务器行为的小示例项目,因为您最有可能在这里处理线程。
答案 1 :(得分:0)
第一个问题:您的应用程序很可能没有收到UDP包。如果serverSocket.accept()没有得到任何客户端,它将无限期地等待某人连接。您可以通过使用另一个只接受连接的线程来避免这种情况,以避免冻结您的应用程序。另一种方法是使用Java的NIO类,为几乎任何东西提供非阻塞IO。这将要求您使用ServerSocketChannel和相关的类。 (快速谷歌搜索也给了我this guide,这似乎很容易遵循)。
第二个问题:完成后,您需要关闭ServerSocket。否则,该端口永远不会再空闲以供另一个ServerSocket使用。 或者你可以让Socket保持打开并记住你已经打开它(例如你的类中有一个布尔字段)。