浏览 1221 次
|
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
最后更新时间:2007-09-29 关键字: 网络编程
我指的是在不使用多线程的情况下进行并发处理
具体的情况是,在不使用多线程的情况下,服务器侦听某个端口,在有连接进来的时候会调用某个函数对此连接进行处理,但是由于处理的过程可能会比较长,为了不让后面连接的用户等待,需要此函数能异步返回,而不是阻塞在这个函数。 之所以希望不使用多线程,是因为考虑到同时连接的用户数会比较多,如果用多线程的话,线程创建,销毁和切换的开销会太大。虽然可以使用线程池,但是这样只是省去了创建和销毁线程的开销,线程切换的开销还是会存在,而且线程的数目也不好确定。 .NET中的Socket类有个方法是BeginReceive,这个方法中可以定义一个回调函数,在调用BeginReceive之后,回调函数会被调用,而BeginReceive可以立即返回,因此在不使用多线程的情况下可以实现并发处理。 我要的就是这种效果,请问在Java中怎么实现? 我找了些资料,里面提到用ServerSocketChannel,即NIO可以实现非阻塞,但是我实验了一下,好像不行。 代码如下:
package snake.test.channel;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
class Server {
public static void main(String[] args) {
Reactor re = null;
try {
re = new Reactor(6656);
re.run();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Reactor implements Runnable {
final Selector selector;
final ServerSocketChannel serverSocket;
public int num = 0;
Reactor(int port) throws IOException {
selector = Selector.open();
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(port));
serverSocket.configureBlocking(false);
SelectionKey sk = serverSocket.register(selector,
SelectionKey.OP_ACCEPT);
sk.attach(new Acceptor());
}
public void run() { // normally in a new Thread
try {
while (!Thread.interrupted()) {
selector.select();
Set selected = selector.selectedKeys();
Iterator it = selected.iterator();
while (it.hasNext()) {
dispatch((SelectionKey) (it.next()));
}
selected.clear();
}
} catch (IOException ex) { /* ... */
}
}
void dispatch(SelectionKey k) {
Runnable r = (Runnable) (k.attachment());
if (r != null)
r.run();
}
class Acceptor implements Runnable { // inner
public void run() {
try {
num++;
SocketChannel c = serverSocket.accept();
if (c != null)
new Handler(selector, c, num);
} catch (IOException ex) { /* ... */
}
}
}
}
package snake.test.channel;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
final class Handler implements Runnable {
final SocketChannel socket;
final SelectionKey sk;
ByteBuffer input = ByteBuffer.allocate(1024);
ByteBuffer output = ByteBuffer.allocate(1024);
static final int READING = 0, SENDING = 1;
int state = READING;
private int num = 0;
Handler(Selector sel, SocketChannel c,int n) throws IOException {
System.out.println("Client Startup");
socket = c;
num = n;
c.configureBlocking(false);
// Optionally try first read now
sk = socket.register(sel, 0);
sk.attach(this);
sk.interestOps(SelectionKey.OP_READ);
sel.wakeup();
}
boolean inputIsComplete() {
return true; /* ... */
}
boolean outputIsComplete() {
return true; /* ... */
}
void process() {
//System.out.println("Sleep");
try {
Thread.sleep(100000000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// class Handler continued
public void run() {
try {
System.out.println("Run " + num);
if (state == READING)
read();
else if (state == SENDING)
send();
} catch (IOException ex) { /* ... */
}
}
void read() throws IOException {
socket.read(input);
if (inputIsComplete()) {
process();
state = SENDING;
// Normally also do first write now
sk.interestOps(SelectionKey.OP_WRITE);
}
}
void send() throws IOException {
socket.write(output);
if (outputIsComplete())
sk.cancel();
}
}
Handler类中的process函数中调用了Thread.Sleep让程序睡眠一段长时间,如果可以异步返回的话,则多个用户可以并发处理,但是不成功 请问是否少了什么东西? 或者有什么别的技术?还是说一定使用多线程技术? 谢谢! 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2007-09-29
nio是符合你的要求,建议你还是找找相关资料吧。下面是一个小例子:
package com.ray.demo.nio1;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class SimpleEchoServer {
private ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
public void acceptConnections(int port) throws Exception {
Selector selector = Selector.open();
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress(port);
server.socket().bind(isa);
server.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
Set readyKeys = selector.selectedKeys();
Iterator i = readyKeys.iterator();
while (i.hasNext()) {
SelectionKey sk = (SelectionKey) i.next();
if (sk.isAcceptable()) {
acceptClient(sk, selector);
}
if (sk.isReadable()) {
dealWithClientRead(sk, selector);
}
i.remove();
}
}
}
private void acceptClient(SelectionKey sk, Selector selector) throws IOException {
ServerSocketChannel nextReady = (ServerSocketChannel) sk.channel();
SocketChannel sc = nextReady.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
}
private void dealWithClientRead(SelectionKey sk, Selector selector) throws IOException {
SocketChannel sockChannel = (SocketChannel) sk.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
readBuffer.clear();
while (sockChannel.read(readBuffer) > 0)
;
readBuffer.flip();
sockChannel.register(selector, SelectionKey.OP_WRITE, readBuffer);
while(readBuffer.hasRemaining()) {
sockChannel.write(readBuffer);
}
}
public static void main(String[] args) throws Exception {
SimpleEchoServer server = new SimpleEchoServer();
server.acceptConnections(1234);
}
}
不过话又说回来,如果你的处理过程是比较花时间的话,例如读数据库等,建议还是使用多线程吧。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-09-29
liangguanhui 写道 nio是符合你的要求,建议你还是找找相关资料吧。下面是一个小例子:
private void dealWithClientRead(SelectionKey sk, Selector selector) throws IOException {
SocketChannel sockChannel = (SocketChannel) sk.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
readBuffer.clear();
while (sockChannel.read(readBuffer) > 0)
;
readBuffer.flip();
sockChannel.register(selector, SelectionKey.OP_WRITE, readBuffer);
while(readBuffer.hasRemaining()) {
sockChannel.write(readBuffer);
}
}
不过话又说回来,如果你的处理过程是比较花时间的话,例如读数据库等,建议还是使用多线程吧。 这种做法跟我上面贴的代码基本上是一样的 如果前一个用户在dealWithClientRead中阻塞的话,后面的用户请求是得不到处理的,我试验的做法是在里面加一个Thread.Sleep,让其睡眠一段长时间,结果后面发起连接的用户的请求都得不到处理,要等到前面的连接处理完才能得到处理 其实我要实现的处理过程并不是太花时间,主要的问题是同时连接的用户的数量会比较大,这样的话用多线程我担心系统开销太大,所以希望能有异步返回的做法,如果上面的nio的做法的话,貌似如果有一个用户阻塞的话,就会导致其他用户的请求得不到处理,这样就不是并发了 不知道我对nio的理解有没有错误,但是我自己写了一些类似你贴的代码的试验程序都做不到并发处理 谢谢! |
|
| 返回顶楼 | |
|
最后更新时间:2007-09-30
看看Cindy,javaeye搜索下就有。
|
|
| 返回顶楼 | |
|
最后更新时间:2007-11-27
ssnake 写道 liangguanhui 写道 nio是符合你的要求,建议你还是找找相关资料吧。下面是一个小例子:
private void dealWithClientRead(SelectionKey sk, Selector selector) throws IOException {
SocketChannel sockChannel = (SocketChannel) sk.channel();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
readBuffer.clear();
while (sockChannel.read(readBuffer) > 0)
;
readBuffer.flip();
sockChannel.register(selector, SelectionKey.OP_WRITE, readBuffer);
while(readBuffer.hasRemaining()) {
sockChannel.write(readBuffer);
}
}
不过话又说回来,如果你的处理过程是比较花时间的话,例如读数据库等,建议还是使用多线程吧。 这种做法跟我上面贴的代码基本上是一样的 如果前一个用户在dealWithClientRead中阻塞的话,后面的用户请求是得不到处理的,我试验的做法是在里面加一个Thread.Sleep,让其睡眠一段长时间,结果后面发起连接的用户的请求都得不到处理,要等到前面的连接处理完才能得到处理 其实我要实现的处理过程并不是太花时间,主要的问题是同时连接的用户的数量会比较大,这样的话用多线程我担心系统开销太大,所以希望能有异步返回的做法,如果上面的nio的做法的话,貌似如果有一个用户阻塞的话,就会导致其他用户的请求得不到处理,这样就不是并发了 不知道我对nio的理解有没有错误,但是我自己写了一些类似你贴的代码的试验程序都做不到并发处理 谢谢! NIO 只是在进行IO操作的时候 不 block calling thread. 业务处理可以用thread pool |
|
| 返回顶楼 | |
|
最后更新时间:2008-09-18
socket.getInputstream().avaible()
loop for : avaible()>0 |
|
| 返回顶楼 | |








