我正在尝试做一些可能很愚蠢的事情,但我认为这是一个好主意,所以请耐心等待。我试图实现它,但是我遇到了一个棘手的问题,在线程之间关闭套接字 - 所以我想要对案例有一些新的看法。
我想通过套接字从Client
到Server
写一个对象。可能会有多个Client
同时与Server
进行通信。
对象Message
由Server
通过其处理机制处理。建议不是Server
的主线程寻找新的传入连接,而是建立Listener
线程。一旦发现传入连接,它就会向Server
发出警报,将套接字存储在队列中而不接收数据,因此它可以快速恢复监听。
在它自己的时间内,Server
选择等待套接字,生成一个新线程,读取Message
,然后关闭套接字。
以下是我应该如何实施的第一个想法。它有一个根本性的缺陷,我将在下面解释。
忽略公共字段的使用 - 我只是想让你们的代码缩短
public class Server {
public boolean messageWaiting = false;
public static void main(String[] args) {
new Server().run();
}
public void run() {
Listener l = new Listener();
l.listen(this);
try {
while (true) {
System.out.println("I'm happily doing my business!");
Thread.sleep(1000);
if (messageWaiting) {
acceptMessages(l);
}
}
} catch (InterruptedException die) {}
}
private void acceptMessages(Listener l) {
while (!l.waiting.isEmpty()) {
try (
Socket client = l.waiting.poll();
ObjectInputStream ois = new ObjectInputStream(client.getInputStream())
) {
// Handle messages in new threads! (or a thread pool)
new Thread() {
public void run() {
try {
System.out.println(ois.readObject());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}.start();
} catch (Exception ex) {
// Oh no! The socket has already been closed!
ex.printStackTrace();
}
}
}
}
public class Listener {
public ConcurrentLinkedQueue<Socket> waiting = new ConcurrentLinkedQueue<>();
public void listen(final Server callback) {
new Thread() {
public void run() {
try (ServerSocket rxSock = new ServerSocket(7500)) {
while (!isInterrupted()) {
try (Socket client = rxSock.accept()) {
// Once a new socket arrives, add it to the waiting queue
waiting.add(client);
// Alert the server
callback.messageWaiting = true;
} catch (IOException ex) {
ex.printStackTrace();
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}.start();
}
}
public class Client {
public static void main(String[] args) {
try (
Socket txSock = new Socket(InetAddress.getLoopbackAddress(), 7500);
ObjectOutputStream oos = new ObjectOutputStream(txSock.getOutputStream())
) {
oos.writeObject("This is a Message, trust me.");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
此:
I'm happily doing my business!
I'm happily doing my business!
java.net.SocketException: Socket is closed
at java.net.Socket.getInputStream(Unknown Source)
at Server.acceptMessages(Server.java:30)
at Server.run(Server.java:20)
at Server.main(Server.java:9)
这是因为我使用的Java 7尝试块在完成后关闭套接字。那我为什么不手动这样做呢?试试你自己 - 你最后会发出警告说你只会在空对象上调用close()!
那么,如何避免在Server
线程接收之前关闭传入套接字的整个问题?或者这是一个坏主意,我应该做点什么呢?
答案 0 :(得分:1)
您在Listener
try (Socket client = rxSock.accept()) { ...
是客户端套接字的try-with-resources。只要将其添加到队列并退出try块,套接字就会自动关闭。