Non-Blocking SocketChannel的问题

masterz 2002-11-30 02:12:09
Non-Blocking SocketChannel的问题挺难伺候的,请大家帮忙。我的服务程序目的是通过ServerSocketChannel监听来自客户端的请求,客户端发一个文件名给服务器,服务器吧这个文件的内容送给客户端,很简单,但一定要用Non-Blocking SocketChannel实现。测试的时候请用大文件测试(文件大于100K).为什么我要用2个Selector?因为一个Selector我没有成功,看到Sun一段代码(可惜不能直接运行测试的)用2个Selector,所以我依样做,还是不成功。
//server side SelectorTestServer.java
/**
http://access1.sun.com/codesamples/Selectors/selectors.html
* This example demostrate use of multiple Selectors() with a single SocketChannel.
* There are two threads running Selectors() each registered for READ and WRITE respectively
*/

import java.net.*;
import java.io.*;
import java.util.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.nio.channels.spi.SelectorProvider;
import java.nio.*;
public class SelectorTestServer {
/** Single selector for accepts, reads */
private Selector readSelector = null;
/** Single selector for writes */
private Selector writeSelector = null;
/** ServerSocketChannel which listens for client connections*/
private ServerSocketChannel ssch = null;
/** The thread that waits for ready Channels - accept / read*/
private SelectorThread readThread = null;
/** The thread that waits for ready Channels - write*/
private WriteThread writeThread = null;
/** Thread which runs the Selector */
private class SelectorThread extends Thread {
private int eventCount;
public SelectorThread() {
super("SelectorThread");
System.out.println("SelectorThread handle OP_ACCEPT|OP_WRITE event");
}
public void run () {
boolean running = true;
try{
eventCount=0;
while(readSelector.select() > 0){
eventCount++;
System.out.println("Read Thread while loop,eventCount="+eventCount);
Set readyKeys = readSelector.selectedKeys();
Iterator i = readyKeys.iterator();
while (i.hasNext()){
SelectionKey sk = (SelectionKey) i.next();
i.remove();
if (sk.isAcceptable()){
// new client connection
ServerSocketChannel nextReady = (ServerSocketChannel) sk.channel();
SocketChannel channel = nextReady.accept();
channel.configureBlocking(false);
channel.register(readSelector, SelectionKey.OP_READ);
writeSelector.wakeup(); // Added as required by specs
channel.register(writeSelector, SelectionKey.OP_WRITE);
addTask(channel);
}
else if (sk.isReadable())
{
System.out.println("****** readable");
doWork(sk);
}
}
}
}
catch (Exception ex){
System.out.println("Exception in selector loop: "+ex.toString());
running = false;
}
} //end run()
} //end class

/** Thread which runs the Selector */
private class WriteThread extends Thread {
private int eventCount;
public WriteThread() {
super("WriteThread");
System.out.println("WriteThread handle OP_WRITE event");
}

public void run () {
boolean running = true;
try{
// block until a Channel is ready for I/O
eventCount=0;
while(writeSelector.select() > 0){
eventCount++;
System.out.println("Write Thread while loop,event count:"+eventCount);
Set readyKeys = writeSelector.selectedKeys();
Iterator i = readyKeys.iterator();
while (i.hasNext()){
SelectionKey sk = (SelectionKey) i.next();
i.remove();
if (sk.isWritable()){
System.out.println("******* writable");
doWork(sk);
}
}
}
}
catch (Exception ex){
System.out.println("Exception in write selector loop: "+ex.toString());
running = false;
}
} //end run()
} //end class
private void doWork(SelectionKey sk)
{
Task t=getTask(sk);
if(t!=null)
{
t.activate(sk);
t.work();
if(t.isFinished())
deleteTask(t);
}

}
/** Stop the selector thread*/
public synchronized void stop () {
try {
this.ssch.close();
}
catch (Exception e) {
System.err.println("Exception in stop()"+e.toString());
}
this.ssch = null;
}

/**
Sets up the selectors and starts listening
*/
protected void startListening () {
try{
// create the selector and the ServerSocket
readSelector = SelectorProvider.provider().openSelector();
writeSelector = SelectorProvider.provider().openSelector();
ssch = ServerSocketChannel.open();
ssch.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), 4900);
ssch.socket().bind(isa);
ssch.register(readSelector, SelectionKey.OP_ACCEPT);
ssch.register(writeSelector, SelectionKey.OP_ACCEPT);
System.out.println("startListening 4900 port");
}
catch (Exception e){
System.out.println("Error starting listening"+e.toString());
}
this.writeThread = new WriteThread();
this.writeThread.setDaemon(true);
this.writeThread.start();
this.readThread = new SelectorThread();
this.readThread.setDaemon(true);
this.readThread.start();
}

// Test the working

public static void main (String argv[]){
SelectorTestServer s = new SelectorTestServer();
s.startListening();
try{
Thread.currentThread().sleep(500000);
}
catch (Exception e){
System.err.println(e.toString());
}
}
private LinkedList taskQueue=new LinkedList();
private LinkedList activeQueue=new LinkedList();
public synchronized void addTask(SocketChannel sc)
{
Task t =new Task(sc);
taskQueue.addLast(t);
}
public synchronized Task getTask(SelectionKey sk)
{
boolean validchannel=false;
SocketChannel sc=(SocketChannel)sk.channel();
ListIterator li = taskQueue.listIterator();
while(li.hasNext())
{
Task t = (Task)li.next();
if(t.isMe(sc))
{
validchannel=true;
return t;
}
}
return null;
}
public synchronized void deleteTask(Task t)
{
taskQueue.remove(t);
}
private static long lastmessagetime=0;
public static void debugMsg(String s)
{
// long lt=System.currentTimeMillis();
// if(lt-lastmessagetime>1000)
// {
// System.out.println(s);
// lastmessagetime=lt;
// }
System.out.println(s);
}

}
...全文
169 20 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
foreversun 2002-12-13
  • 打赏
  • 举报
回复
masterz:
你真的很厉害啊,太佩服了
ggzzkk 2002-12-03
  • 打赏
  • 举报
回复
ServerSocketChannel channel =
ServerSocketChannel.open();
channel.configureBlocking(false);
InetSocketAddress isa = new InetSocketAddress(port);
channel.socket().bind(isa);

//把ServerSocketChannel注册到通道,产生OP_ACCEPT事件
channel.register(selector, SelectionKey.OP_ACCEPT);

while (selector.select() > 0) {
Set readyKeys = selector.selectedKeys();
Iterator readyItor = readyKeys.iterator();
while (readyItor.hasNext()) {
SelectionKey key = (SelectionKey)readyItor.next();
readyItor.remove();
if (key.isAcceptable()) {
ServerSocketChannel keyChannel = (ServerSocketChannel)key.channel();
SocketChannel channel = keyChannel.accept();
channel.configureBlocking(false);
//在通道注册OP_READ事件
channel.register(selector, SelectionKey.OP_READ);
}else if (key.isReadable()) {
SocketChannel keyChannel = (SocketChannel)key.channel();
..........................
}
}

客户端Socket连接服务器端,就会产生OP_ACCEPT事件的发生,这时会执行这句channel.register(selector, SelectionKey.OP_READ);那么while (selector.select() > 0) 为true,然后又会执行if (key.isReadable())中的代码,可这时客户端Socket并没有write操作,这样就会发生错误。那该如何解决呢?
远太狼 2002-12-03
  • 打赏
  • 举报
回复
你的服务器端的selector用法好像有点错, 为什么把serverSocketChannel注册到两个selector中阿?
skyyoung 2002-12-02
  • 打赏
  • 举报
回复
http://www.javaworld.com/javaworld/jw-09-2001/jw-0907-merlin_p.html
XKP 2002-12-01
  • 打赏
  • 举报
回复
这个例子实在是好长·········
IBM的那个好像是有点问题·······
最近在看JDK14 Tutorial
里面有这方面的例子,不过当然比这个简单了
只有大约4K,或许你可以去参考参考?
realdreamer 2002-12-01
  • 打赏
  • 举报
回复
非阻塞套接字通道?

不懂啊.

给你 UP
huzhangyou 2002-12-01
  • 打赏
  • 举报
回复
实在是不会
up
RomanticProgrammer 2002-12-01
  • 打赏
  • 举报
回复
up
masterz 2002-12-01
  • 打赏
  • 举报
回复
post a working one, but not multithreaded.
import java.nio.*;
import java.net.*;
import java.nio.channels.*;
import java.io.*;
import java.util.*;
import java.nio.charset.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
class Reactor implements Runnable {
final Selector selector;
final ServerSocketChannel serverSocket;
Reactor(int port) throws IOException {
selector = Selector.open();
serverSocket = ServerSocketChannel.open();
serverSocket.socket().bind(new InetSocketAddress(port));
System.out.println(this.getClass().getName()+" listen on port "+port);
serverSocket.configureBlocking(false);
SelectionKey sk =serverSocket.register(selector,SelectionKey.OP_ACCEPT);
sk.attach(new Acceptor());
}

public static void main(String args[])
{
new NonBlockingTestClient().show();
try
{ new Reactor(4900).run();}
catch (IOException ex) { ex.printStackTrace(); }
}
/*
Alternatively, use explicit SPI provider:
SelectorProvider p = SelectorProvider.provider();
selector = p.openSelector();
serverSocket = p.openServerSocketChannel();
http://gee.cs.oswego.edu
*/

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) { ex.printStackTrace(); }
}
void dispatch(SelectionKey k) {
Runnable r = (Runnable)(k.attachment());
if (r != null)
r.run();
}


// class Reactor continued
class Acceptor implements Runnable { // inner
public void run() {
try {
SocketChannel c = serverSocket.accept();
if (c != null)
new Handler(selector, c);
}
catch(IOException ex) { ex.printStackTrace();}
}
}
}


final class Handler implements Runnable {
final SocketChannel socket;
final SelectionKey sk;
static final int MAXIN=1024;
static final int MAXOUT=1024;
ByteBuffer inputData = ByteBuffer.allocate(MAXIN);
ByteBuffer output = ByteBuffer.allocate(MAXOUT);
static final int READING = 0, SENDING = 1;
int state = READING;
Handler(Selector sel, SocketChannel c)
throws IOException {
socket = c;
// Optionally try first read now
socket.configureBlocking(false);
sk = socket.register(sel, SelectionKey.OP_READ);
sk.attach(this);
sk.interestOps(SelectionKey.OP_READ);
sel.wakeup();
}
private String fileName;
boolean isNeedRead()
{
if(fileName!=null&&fileName.endsWith(".zip"))
return false;
int len=inputData.position();
if(len<=0)
return true;
inputData.flip();
String stmp="void";
try
{
Charset set = Charset.forName("us-ascii");
CharsetDecoder dec = set.newDecoder();
CharBuffer charBuf = dec.decode(inputData);
stmp=charBuf.toString();
}
catch(Exception e)
{
e.printStackTrace();
}
if(stmp.endsWith(".zip"))
{
fileName = stmp;
debugMsg("needRead():"+fileName+";inputData.position:"+len);
return false;
}
inputData.rewind();
inputData.position(len);
return true;
}
void debugMsg(String s)
{
System.out.println(s);
}
boolean inputIsComplete()
{
return !isNeedRead();
}
boolean outputIsComplete() { if(fileLength==totalSend) return true; return false;}
void process()
{
if(fc==null)
{//open the file
try
{
fileLength =0;
totalSend=0;
File file = new File(fileName);
RandomAccessFile rdm = new RandomAccessFile(file,"r");
fc = rdm.getChannel();
fileLength = file.length();
}
catch(Exception e)
{
debugMsg("init() filename="+fileName);
e.printStackTrace();
}
}
}
// class Handler continued
public void run() {
try {
if (state == READING) read();
else if (state == SENDING) send();
} catch (IOException ex) { /* ... */ }
}
void read() throws IOException {
socket.read(inputData);
if (inputIsComplete()) {
process();
state = SENDING;
// Normally also do first write now
sk.interestOps(SelectionKey.OP_WRITE);
}
}
private long fileLength;
private long totalSend;
private FileChannel fc ;
void send() throws IOException {

if(fc==null)
{
sk.cancel();
debugMsg("unable to open file, cancel this connection");
return;
}
output.clear();
fc.position(totalSend);
fc.read(output);
output.flip();
int sendcount=socket.write(output);
if(sendcount>0)
{
totalSend+=sendcount;
}
debugMsg("send "+sendcount+" bytes");
if (outputIsComplete()) sk.cancel();
}
}

class NonBlockingTestClient extends javax.swing.JFrame
{
int MAXTHREAD = 2;
JTextField jtfFileName=new JTextField("C:\\tmp\\googleapi.zip");
public NonBlockingTestClient(){
JButton jb=new JButton("send 2 request");
Container c=getContentPane();
c.setLayout(new GridLayout(0,1));
c.add(jtfFileName);c.add(jb);
jb.addActionListener(new java.awt.event.ActionListener()
{public void actionPerformed(ActionEvent e)
{ work(); }});
setSize(new Dimension(400,400));
setVisible(true);
pack();
}
public static void main(String args[])
{
NonBlockingTestClient ntc=new NonBlockingTestClient();
}
private void work()
{
for(int i=0;i<2;i++)
new Thread(new Request()).start();
}
public static int threadcount=0;
public synchronized int incCount()
{
threadcount++;
return threadcount;
}
class Request implements Runnable
{
private int ID;
public Request()
{
ID=incCount();
}
public void run()
{
try
{
InetAddress ia = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(ia,4900);
Socket skt = new Socket();
skt.connect(isa);
;
System.out.println("connect to :"+isa);
OutputStream os=skt.getOutputStream();
//os.write("C:\\tmp\\googleapi.zip".getBytes());
os.write(jtfFileName.getText().getBytes());
os.flush();
InputStream is=skt.getInputStream();
System.out.println("request of thread "+ID+",port="+skt.getLocalPort()+" send to server");
byte b[]=new byte[1024];
int read=0;
FileOutputStream fos=new FileOutputStream(new File(""+ID+".zip"));
do
{
read=is.read(b,0,1024);
System.out.println("thread "+ID+" read "+read);
if(read>0)
fos.write(b,0,read);
}
while(read>0);
fos.close();
is.close();
os.close();
}
catch(Exception e)
{e.printStackTrace();}
}
}
}
xiaosanshao0419 2002-12-01
  • 打赏
  • 举报
回复
太长了,我现在正忙,过会看。
松耦合紧内聚 2002-11-30
  • 打赏
  • 举报
回复
五星上将呀!这么厉害!
masterz 2002-11-30
  • 打赏
  • 举报
回复
anybody involves in network programming?
dentance 2002-11-30
  • 打赏
  • 举报
回复
I am so tired.
masterz 2002-11-30
  • 打赏
  • 举报
回复
http://www-106.ibm.com/developerworks/java/library/j-javaio/?dwzone=java
Merlin brings nonblocking I/O to the Java platform
IBM的文章我看过了,那个家伙闭着眼睛瞎写,有下面这个大大的bug,他竟然能把那篇吹nonblocking I/O的文章写出来,我晕
http://developer.java.sun.com/developer/bugParade/bugs/4755720.html
Bug Id 4755720
Votes 4
Synopsis registering OP_WRITE in nio 1.4.1 prevents selection of OP_READ events
masterz 2002-11-30
  • 打赏
  • 举报
回复
朋友们,我的服务器端程序11k,客户端程序2k,保存下来可以直接运行的。help help help
wjmmml 2002-11-30
  • 打赏
  • 举报
回复
太长了,我现在正忙验收项目等,实在没有时间,等忙完了,在看看看
yoyoxo 2002-11-30
  • 打赏
  • 举报
回复
gz
basai 2002-11-30
  • 打赏
  • 举报
回复
太长了,先帮你up
再慢慢看
masterz 2002-11-30
  • 打赏
  • 举报
回复
//client side test program
import java.io.*;
import java.net.*;

public class NonBlockingTestClient
{
int MAXTHREAD = 2;
public static void main(String args[])
{
NonBlockingTestClient ntc=new NonBlockingTestClient();
for(int i=0;i<2;i++)
new Thread(ntc.new Request()).start();
}
public static int threadcount=0;
public synchronized int incCount()
{
threadcount++;
return threadcount;
}
class Request implements Runnable
{
private int ID;
public Request()
{
ID=incCount();
}
public void run()
{
try
{
InetAddress ia = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(ia,4900);
Socket skt = new Socket();
skt.connect(isa);
System.out.println("connect to :"+isa);
OutputStream os=skt.getOutputStream();
os.write("C:\\tmp\\googleapi.zip".getBytes());
os.flush();
InputStream is=skt.getInputStream();
System.out.println("request of thread "+ID+" send to server");
byte b[]=new byte[1024];
int read=0;
FileOutputStream fos=new FileOutputStream(new File(""+ID+".zip"));
do
{
read=is.read(b,0,1024);
System.out.println("thread "+ID+" read "+read);
if(read>0)
fos.write(b,0,read);
}
while(read>0);
fos.close();
is.close();
os.close();
}
catch(Exception e)
{e.printStackTrace();}
}
}
}
masterz 2002-11-30
  • 打赏
  • 举报
回复
class Task
{
private SocketAddress clientAddr;
private String filename;
private long lastActiveTime;
private long createTime;
private ByteBuffer inputData;
private boolean needFlip;
public Task()
{
inputData = ByteBuffer.allocate(1024);
needFlip = true;
totalwrite=0;
}
public Task(SocketChannel sc)
{
inputData = ByteBuffer.allocate(1024);
needFlip = true;
if(sc!=null)
{
Socket s = sc.socket();
lastActiveTime = System.currentTimeMillis();
createTime = lastActiveTime;
clientAddr=s.getRemoteSocketAddress();
}
}
private SelectionKey key;
public void activate(SelectionKey sk)
{
key =sk;
}
public void deactivate()
{
key =null;
}

public boolean isMe(SocketChannel sc)
{
if(clientAddr==null)
return false;
Socket s = sc.socket();
return s.getRemoteSocketAddress().equals(clientAddr);
}
private boolean needRead()
{
if(filename!=null&&filename.length()>3)
return false;
int len=inputData.position();
if(len<=0)
return true;
inputData.flip();
String stmp="void";
try
{
Charset set = Charset.forName("us-ascii");
CharsetDecoder dec = set.newDecoder();
CharBuffer charBuf = dec.decode(inputData);
stmp=charBuf.toString();
}
catch(Exception e)
{
e.printStackTrace();
}
inputData.rewind();
inputData.position(len);
if(stmp.endsWith(".zip"))
{
filename = stmp.substring(stmp.length()-20);
debugMsg("needRead():"+filename+";inputData.position:"+len);
return false;
}
return true;
}

public void work()
{
if(key==null)
return;
if(needRead())
readMessage(key);
if(!needRead())
writeMessage(key);
deactivate();
}

private void readMessage(SelectionKey key)
{
needFlip = true;
int nBytes = 0;
totalwrite =0;
SocketChannel socket = (SocketChannel)key.channel();
try
{
// do
// {
nBytes = socket.read(inputData);
debugMsg("readMessage() read :"+nBytes+" from "+getChannelAddress(socket));
// }
// while(nBytes>0);
}
catch(IOException e)
{
e.printStackTrace();
}
}
public boolean isTimeOut()
{
if(System.currentTimeMillis()-lastActiveTime>1000*30)
return true;
return false;
}
private int writeTime =0;
public boolean isFinished()
{
//call this at every writeMessage()
if(writeTime<=0)
return false;
if(filelength==totalwrite)
{
return true;
}
return false;
}
public void destroy()
{
key=null;
writeTime = 0;
lastActiveTime = 0;
createTime = 0;
clientAddr = null;
inputData.rewind();
needFlip = true;
totalwrite = 0;
try
{
fc.close();
}
catch(Exception e)
{
e.printStackTrace();
}
fc = null;
}
public void init()
{
if(fc!=null)
return;
System.out.println("Task.init(), open the file for the first write action");
needRead();
try
{
File file;
file = new File(filename);
RandomAccessFile rdm = new RandomAccessFile(file,"r");
fc = rdm.getChannel();
// buffer = ByteBuffer.allocate(1024);
filelength = file.length();
}
catch(Exception e)
{
System.out.println("init() filename="+filename);
e.printStackTrace();
}
totalwrite = 0;
}
// private
// private RandomAccessFile rdm;
// private ByteBuffer buffer;
private FileChannel fc ;
private long filelength;
private int totalwrite;
private void writeMessage(SelectionKey key)
{
init();
if(fc==null)
return;
ByteBuffer buffer=ByteBuffer.allocate(1600);
writeTime++;
if(needFlip)
{
inputData.flip();
needFlip=false;
}
lastActiveTime = System.currentTimeMillis();
SocketChannel socket = (SocketChannel)key.channel();
try
{
int nBytes=0;
// do
// {
fc.position(totalwrite);
buffer.rewind();
fc.read(buffer);
buffer.flip();
nBytes = socket.write(buffer);
buffer.rewind();
if(nBytes>0)
{
totalwrite+=nBytes;
}
debugMsg("Task.writeMessage() nBytes = "+nBytes+";address="+getChannelAddress(socket));
// else
// {
// System.out.println("error in Task.writeMessage,nBytes = "+nBytes);
// System.out.println("socket close here due to write error");
// destroy();
// socket.close();
// }
// }
// while(nBytes>0 &&isFinished()==false);
if(isFinished())
{
System.out.println("the while file has been sent by Task.writeMessage");
}

}
catch(Exception e)
{
e.printStackTrace();
}

}
private static void debugMsg(String s)
{
SelectorTestServer.debugMsg(s);
}
public static String getChannelAddress(SocketChannel sc)
{
Socket s = sc.socket();
StringBuffer sb = new StringBuffer();
sb.append("peer address:");
sb.append(s.getRemoteSocketAddress().toString());
return sb.toString();
}
}
//end of SelectorTestServer.java

62,634

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧