使用javanio从阻塞转换为非阻塞I / O.

时间:2011-03-28 13:33:42

标签: java sockets stream io nio

我调整此代码How to send and receive serialized object in socket channel我的实时模拟发送对象,但我一个接一个地遇到异常,因为这个代码本质上阻止了如何使用javanio将此代码转换为非阻塞

  /*
     * Writer
     */
    import java.io.IOException;
    import java.io.ObjectOutputStream;
    import java.net.InetSocketAddress;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;

    public class CleanSender implements Runnable {

        private SimManager SM;
        private BallState ballState = new BallState(10, 5);
        private ServerSocketChannel ssChannel;

        private Thread tRunSer = new Thread(this, "ServerSelectThread");

    public static void main(String[] args) throws IOException {

        CleanSender server = new CleanSender();
        server.startServer();

    }

    private void startServer() throws IOException {
        ssChannel = ServerSocketChannel.open();
        ssChannel.configureBlocking(true);
        int port = 2345;
        ssChannel.socket().bind(new InetSocketAddress(port));
        // SM = new SimManager(this, BS);
        // SM.start(); // GameEngine thread starting here
        tRunSer.start();
    }

    public void run() {
        try {
            SocketChannel sChannel = ssChannel.accept();

            while (true) {

                ObjectOutputStream oos = new ObjectOutputStream(sChannel
                        .socket().getOutputStream());
                oos.writeObject(ballState);
                System.out.println("Sending String is: '" + ballState.X + "'" + ballState.Y);
                oos.close();
                System.out.println("Sender Start");
                System.out.println("Connection ended");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户:持续寻找来自服务器的回复

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;

public class CleanReceiver implements Runnable {

    private SocketChannel sChannel;
    private Thread receiverThread = new Thread(this, "receiverThread");


    private synchronized  void startServer() throws IOException {
         sChannel = SocketChannel.open();
         sChannel.configureBlocking(true);
         if (sChannel.connect(new InetSocketAddress("localhost", 2345))) {
             receiverThread.start();
         }
    }
public void run() {

    while (true) {
        try {
            ObjectInputStream ois = new ObjectInputStream(sChannel.socket()
                    .getInputStream());

            BallState s = (BallState) ois.readObject();
            System.out.println("String is: '" + s.X + "'" + s.Y);
            ois.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        System.out.println("End Receiver");
    }
}


      public static void main(String[] args) 
        throws IOException, ClassNotFoundException {

            CleanReceiver rc=new CleanReceiver();
            rc.startServer();

            System.out.println("End Receiver");
        }
}

此设计是否会在服务器必须保持连接客户端并同时将模拟状态发送到已连接的客户端的情况下工作? ,我正在寻找专家一眼。

感谢,

jibbylala

2 个答案:

答案 0 :(得分:1)

如果您正在使用ObjectInputStream或ObjectOutputStream,我建议您坚持使用阻止IO。对这些库使用非阻塞IO比没有真正的好处困难10倍。

您是否考虑过使用ServerSocketSocket代替NIO。这些将更容易使用,以及对象流源自设计使用的内容,

答案 1 :(得分:0)

您的代码有两个主要问题:

  • 在处理每个对象后关闭流,导致关闭相关套接字,因此它们不再有效,不能用于处理以下对象。在接收端,您根本不需要在循环内close(),在发送方使用flush()而不是close()来确保刷新缓冲区。

  • 实现阻塞IO时,您(通常)需要在服务器上为每个客户端启动一个新线程。它允许您同时与多个客户端通信。在这种情况下要小心线程同步问题!

如果每个客户端都有一个线程是不可接受的,你可以以非阻塞的方式实现服务器,但正如Peter Lawrey已经说过的那样,它更复杂,所以我建议你让它与阻塞IO一起工作第一