使用 javanio 从阻塞 I/O 转变为非阻塞 I/O
我改编此代码 如何发送和接收序列化套接字通道中的对象 我实时模拟发送对象,但我一个接一个地遇到异常,是因为这段代码本质上是阻塞的,如何使用 javanio Client 将这段代码转换为非阻塞
/*
* 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");
}
}
在服务器必须保持连接客户端并同时将模拟状态发送到已连接的客户端的情况下,此设计是否有效?,我正在寻找专家浏览。
谢谢,
吉比拉拉
i adapt this code How to send and receive serialized object in socket channel my real time simulation to send objects but i am running into exceptions one after another is it because this code blocking in nature how this code can be converted in to non blocking with 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();
}
}
}
Client: which is continously looking for reply from server
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");
}
}
Will this design work in the scenario when server has to keep connect the client and simultaneous send the simulation state to already connected client?, i m looking for experts glance.
thanks,
jibbylala
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您使用 ObjectInputStream 或 ObjectOutputStream,我建议您坚持使用阻塞 IO。在这些库中使用非阻塞 IO 会困难 10 倍,而且没有任何实际好处。
您是否考虑过使用
ServerSocket
和Socket
来代替NIO。这些将更容易使用以及对象流最初设计的用途,If you are using ObjectInputStream or ObjectOutputStream I suggest you stick with blocking IO. Using non-blocking IO with these libraries is 10x harder for no real benifit.
Have you considered using
ServerSocket
andSocket
instead of NIO. These will be easier to use and what the object streams were originall designed to use,您的代码有两个主要问题:
在处理每个单个对象后关闭流,这会导致关联的套接字关闭,因此它们不再有效并且不能用于处理以下对象。在接收端,您根本不需要在循环内使用
close()
,在发送端使用flush()
而不是close() 以确保刷新缓冲区。
当实现阻塞 IO 时,您(通常)需要在服务器上为每个客户端启动一个新线程。它将允许您同时与多个客户进行通信。在这种情况下要小心线程同步问题!
如果每个客户端有一个线程对您来说是不可接受的,您可以以非阻塞方式实现服务器,但是,正如 Peter Lawrey 已经说过的,它更复杂,所以我建议您首先让它与阻塞 IO 一起工作。
Your code have two main problems:
You close streams after handling every single object, that causes closing of the associated sockets, so they are no longer valid and cannot be used for processing the following objects. At the receiving side you don't need
close()
inside a loop at all, at the sending side useflush()
instead ofclose()
to ensure that buffers are flushed.When implementing blocking IO you (usually) need to start a new thread on the server for each client. It would allow you to communicate with multiple clients simultaneously. Beware of thread synchronization problems in this case!
If having a thread per client is not acceptable for you, you can implement server in a non-blocking way, but, as already said by Peter Lawrey, it's more complex, so I suggest you to get it working with blocking IO first.