2

我正在尝试做一些可能很愚蠢的事情,但我认为这是个好主意,所以请耐心等待。我试图实现它,但我遇到了一个尴尬的问题,即线程之间的套接字关闭 - 所以我想对这个案例有一些新的看法。

设想

我想通过套接字将对象从 a 写入Clienta 。Server可能有不止一个ClientServer并发通信。

对象 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线程启动之前关闭传入套接字的整个问题?或者这是一个坏主意,我应该做点别的吗?

4

1 回答 1

1

你的陈述在Listener

try (Socket client = rxSock.accept()) { ...

客户端套接字的 try-with-resources。一旦将其添加到队列并退出 try 块,套接字就会自动关闭。

于 2013-05-07T22:48:49.857 回答