我正在尝试做一些可能很愚蠢的事情,但我认为这是个好主意,所以请耐心等待。我试图实现它,但我遇到了一个尴尬的问题,即线程之间的套接字关闭 - 所以我想对这个案例有一些新的看法。
设想
我想通过套接字将对象从 a 写入Client
a 。Server
可能有不止一个Client
与Server
并发通信。
对象 aMessage
通过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 try 块一旦完成就关闭套接字。那我为什么不手动做呢?试试你自己——你最终会得到一个警告,说你只会在一个空对象上调用 close() !
那么,如何避免在Server
线程启动之前关闭传入套接字的整个问题?或者这是一个坏主意,我应该做点别的吗?