我想问一下Selector 的select()和selectedKey()方法,有什么区别我好象感觉这两个方法其实就是一样的啊。。
还有就是,SelectionKey.OP_ATTEPT,SelectionKey.OP_CONNECT,SelectionKey.OP_READ,SelectionKey.OP_WRITE这4个来表示事件。。
SelectionKey.OP_ATTEPT,SelectionKey.OP_CONNECT都好理解。。
后面两个(SelectionKey.OP_READ,SelectionKey.OP_WRITE)就不怎么好理解了:书上书,OP_READ 表示通道中已经存有了可读数据。。那么就执行操作。。通道应该指的是SocketChannel里面吧最难理解的是SelectionKey.OP_WRITE .这是说表示可以向通道里面写数据了。。我要问的是:在什么情况下表示可以象通道里写数据。。而且一般都是先if(SelectionKey.isWritable())为真的时候才写数据我就搞不懂了。。一个程序他是在什么情况下知道要写数据呢??是先写数据他才知道写数据?还是先知道写数据才写数据?下面是个程序import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
class EchoClient{
private SocketChannel socketChannel = null;
private ByteBuffer sendBuffer=ByteBuffer.allocate(1024);
private ByteBuffer receiveBuffer=ByteBuffer.allocate(1024);
private Charset charset=Charset.forName("GBK");
private Selector selector;
public EchoClient()throws IOException{
socketChannel = SocketChannel.open();
InetAddress ia = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(ia,8000);
socketChannel.connect(isa);
socketChannel.configureBlocking(false);
System.out.println("与服务器的连接建立成功");
selector=Selector.open();
}
public static void main(String args[])throws IOException{
final EchoClient client=new EchoClient();
Thread receiver=new Thread(){
public void run(){
client.receiveFromUser();
}
}; receiver.start();
client.talk();
} public void receiveFromUser(){
try{
BufferedReader localReader=new BufferedReader(new InputStreamReader(System.in));
String msg=null;
while((msg=localReader.readLine())!=null){
synchronized(sendBuffer){
sendBuffer.put(encode(msg + "\r\n"));
}
if(msg.equals("bye"))
break;
}
}catch(IOException e){
e.printStackTrace();
}
} public void talk()throws IOException {
socketChannel.register(selector,
SelectionKey.OP_READ |
SelectionKey.OP_WRITE);
//System.out.println("selector.select()1 "+selector.select()); //为什么这里为 1.如果注释掉这句,那么下面一句打出的结果是0,如果执行这句,则下面打错的就是1下面一句指的是selector.selectedKeys().size().... select()到底起到什么作用啊?
System.out.println("selector.selectedKeys()1 "+selector.selectedKeys().size());
// System.out.println("selector.selectedKeys()2 "+selector.selectedKeys().size());
// System.out.println("selector.select()2 "+selector.select());//同一个方法为什么这里为 0 呢?
while (selector.select() > 0 ){
Set readyKeys = selector.selectedKeys();
Iterator it = readyKeys.iterator();
while (it.hasNext()){
SelectionKey key=null;
try{
key = (SelectionKey) it.next();
it.remove(); if (key.isReadable()) {
System.out.println("可以读了");
receive(key);
}
if (key.isWritable()) {
//System.out.println("可以写了"); 客户端连接上之后无限打印.为什么啊? send(key);
}
}catch(IOException e){
e.printStackTrace();
try{
if(key!=null){
key.cancel();
key.channel().close();
}
}catch(Exception ex){e.printStackTrace();}
}
}//#while
}//#while
} public void send(SelectionKey key)throws IOException{
SocketChannel socketChannel=(SocketChannel)key.channel();
synchronized(sendBuffer){
sendBuffer.flip(); //把极限设为位置
socketChannel.write(sendBuffer);
sendBuffer.compact();
}
}
public void receive(SelectionKey key)throws IOException{
SocketChannel socketChannel=(SocketChannel)key.channel();
socketChannel.read(receiveBuffer);
receiveBuffer.flip();
String receiveData=decode(receiveBuffer); if(receiveData.indexOf("\n")==-1)return; String outputData=receiveData.substring(0,receiveData.indexOf("\n")+1);
System.out.print(outputData);
if(outputData.equals("echo:bye\r\n")){
key.cancel();
socketChannel.close();
System.out.println("关闭与服务器的连接");
selector.close();
System.exit(0);
} ByteBuffer temp=encode(outputData);
receiveBuffer.position(temp.limit());
receiveBuffer.compact();
} public String decode(ByteBuffer buffer){ //解码
CharBuffer charBuffer= charset.decode(buffer);
return charBuffer.toString();
}
public ByteBuffer encode(String str){ //编码
return charset.encode(str);
}
}代码里面有些问题,大家也解释一下 。由于篇幅问题服务器程序没写出来
还有就是,SelectionKey.OP_ATTEPT,SelectionKey.OP_CONNECT,SelectionKey.OP_READ,SelectionKey.OP_WRITE这4个来表示事件。。
SelectionKey.OP_ATTEPT,SelectionKey.OP_CONNECT都好理解。。
后面两个(SelectionKey.OP_READ,SelectionKey.OP_WRITE)就不怎么好理解了:书上书,OP_READ 表示通道中已经存有了可读数据。。那么就执行操作。。通道应该指的是SocketChannel里面吧最难理解的是SelectionKey.OP_WRITE .这是说表示可以向通道里面写数据了。。我要问的是:在什么情况下表示可以象通道里写数据。。而且一般都是先if(SelectionKey.isWritable())为真的时候才写数据我就搞不懂了。。一个程序他是在什么情况下知道要写数据呢??是先写数据他才知道写数据?还是先知道写数据才写数据?下面是个程序import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;
class EchoClient{
private SocketChannel socketChannel = null;
private ByteBuffer sendBuffer=ByteBuffer.allocate(1024);
private ByteBuffer receiveBuffer=ByteBuffer.allocate(1024);
private Charset charset=Charset.forName("GBK");
private Selector selector;
public EchoClient()throws IOException{
socketChannel = SocketChannel.open();
InetAddress ia = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(ia,8000);
socketChannel.connect(isa);
socketChannel.configureBlocking(false);
System.out.println("与服务器的连接建立成功");
selector=Selector.open();
}
public static void main(String args[])throws IOException{
final EchoClient client=new EchoClient();
Thread receiver=new Thread(){
public void run(){
client.receiveFromUser();
}
}; receiver.start();
client.talk();
} public void receiveFromUser(){
try{
BufferedReader localReader=new BufferedReader(new InputStreamReader(System.in));
String msg=null;
while((msg=localReader.readLine())!=null){
synchronized(sendBuffer){
sendBuffer.put(encode(msg + "\r\n"));
}
if(msg.equals("bye"))
break;
}
}catch(IOException e){
e.printStackTrace();
}
} public void talk()throws IOException {
socketChannel.register(selector,
SelectionKey.OP_READ |
SelectionKey.OP_WRITE);
//System.out.println("selector.select()1 "+selector.select()); //为什么这里为 1.如果注释掉这句,那么下面一句打出的结果是0,如果执行这句,则下面打错的就是1下面一句指的是selector.selectedKeys().size().... select()到底起到什么作用啊?
System.out.println("selector.selectedKeys()1 "+selector.selectedKeys().size());
// System.out.println("selector.selectedKeys()2 "+selector.selectedKeys().size());
// System.out.println("selector.select()2 "+selector.select());//同一个方法为什么这里为 0 呢?
while (selector.select() > 0 ){
Set readyKeys = selector.selectedKeys();
Iterator it = readyKeys.iterator();
while (it.hasNext()){
SelectionKey key=null;
try{
key = (SelectionKey) it.next();
it.remove(); if (key.isReadable()) {
System.out.println("可以读了");
receive(key);
}
if (key.isWritable()) {
//System.out.println("可以写了"); 客户端连接上之后无限打印.为什么啊? send(key);
}
}catch(IOException e){
e.printStackTrace();
try{
if(key!=null){
key.cancel();
key.channel().close();
}
}catch(Exception ex){e.printStackTrace();}
}
}//#while
}//#while
} public void send(SelectionKey key)throws IOException{
SocketChannel socketChannel=(SocketChannel)key.channel();
synchronized(sendBuffer){
sendBuffer.flip(); //把极限设为位置
socketChannel.write(sendBuffer);
sendBuffer.compact();
}
}
public void receive(SelectionKey key)throws IOException{
SocketChannel socketChannel=(SocketChannel)key.channel();
socketChannel.read(receiveBuffer);
receiveBuffer.flip();
String receiveData=decode(receiveBuffer); if(receiveData.indexOf("\n")==-1)return; String outputData=receiveData.substring(0,receiveData.indexOf("\n")+1);
System.out.print(outputData);
if(outputData.equals("echo:bye\r\n")){
key.cancel();
socketChannel.close();
System.out.println("关闭与服务器的连接");
selector.close();
System.exit(0);
} ByteBuffer temp=encode(outputData);
receiveBuffer.position(temp.limit());
receiveBuffer.compact();
} public String decode(ByteBuffer buffer){ //解码
CharBuffer charBuffer= charset.decode(buffer);
return charBuffer.toString();
}
public ByteBuffer encode(String str){ //编码
return charset.encode(str);
}
}代码里面有些问题,大家也解释一下 。由于篇幅问题服务器程序没写出来
解决方案 »
- [求助]拷贝文件判断条件
- Java Object的clone()方法到底到底做了什么事情?
- thinking in java问题
- 有没有英文原版JAVA教材的电子版?
- struts 中怎样在action中获得ApplicationResourses.properties中国际化字符
- 救急~~~请问怎样在程序中调用别人写好的Action中的actionPerformed(ActionEvent e)中的代码?
- import
- XML 中有这个<!DOCTYPE PLAY SYSTEM "plays.dtd">的数据读取,急
- 杭电ACM 1005 一直报错
- 别人软件包里的文件为什么javac不能通过?
- post方法提交的内容转发问题
- 请教关于linux下java类DateFormat的使用!
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.util.*;public class EchoServer{
private Selector selector = null;
private ServerSocketChannel serverSocketChannel = null;
private int port = 8000;
private Charset charset=Charset.forName("GBK"); public EchoServer()throws IOException{
selector = Selector.open();
serverSocketChannel= ServerSocketChannel.open();
serverSocketChannel.socket().setReuseAddress(true);
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(port));
System.out.println("服务器启动");
} public void service() throws IOException{
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT );
while (selector.select() > 0 ){
Set readyKeys = selector.selectedKeys();
Iterator it = readyKeys.iterator();
while (it.hasNext()){
SelectionKey key=null;
try{
key = (SelectionKey) it.next();
it.remove(); if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = (SocketChannel) ssc.accept();
System.out.println("接收到客户连接,来自:" +
socketChannel.socket().getInetAddress() +
":" + socketChannel.socket().getPort());
socketChannel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
socketChannel.register(selector,
SelectionKey.OP_READ |
SelectionKey.OP_WRITE, buffer);
}
if (key.isReadable()) {
// System.out.println("可以读数据");客户端关闭无限打印为什么啊?
receive(key);
}
if (key.isWritable()) {
// System.out.println("可以写数据");客户端连接上之后无限打印.为什么啊?
send(key);
}
}catch(IOException e){
e.printStackTrace();
try{
if(key!=null){
key.cancel();
key.channel().close();
}
}catch(Exception ex){e.printStackTrace();}
}
}//#while
}//#while
} public void send(SelectionKey key)throws IOException{
ByteBuffer buffer=(ByteBuffer)key.attachment();
SocketChannel socketChannel=(SocketChannel)key.channel();
buffer.flip(); //把极限设为位置,把位置设为0
String data=decode(buffer);
if(data.indexOf("\r\n")==-1)return;
String outputData=data.substring(0,data.indexOf("\n")+1);
System.out.print(outputData);
ByteBuffer outputBuffer=encode("echo:"+outputData);
while(outputBuffer.hasRemaining())
socketChannel.write(outputBuffer); ByteBuffer temp=encode(outputData);
buffer.position(temp.limit());
buffer.compact(); if(outputData.equals("bye\r\n")){
key.cancel();
socketChannel.close();
System.out.println("关闭与客户的连接");
}
} public void receive(SelectionKey key)throws IOException{
ByteBuffer buffer=(ByteBuffer)key.attachment(); SocketChannel socketChannel=(SocketChannel)key.channel();
ByteBuffer readBuff= ByteBuffer.allocate(32);
socketChannel.read(readBuff);
readBuff.flip(); buffer.limit(buffer.capacity());
buffer.put(readBuff);
} public String decode(ByteBuffer buffer){ //解码
CharBuffer charBuffer= charset.decode(buffer);
return charBuffer.toString();
}
public ByteBuffer encode(String str){ //编码
return charset.encode(str);
} public static void main(String args[])throws Exception{
EchoServer server = new EchoServer();
server.service();
}
}
2.第二个问题你就必须要了解AIO和NIO的不同了,如果你用AIO来实现一个SOCKET SERVER 必须要用线程的方式来实现并且会需要很多线程,而采用了NIO技术之后在通道里面实现了选择器技术,而选择器就是用来模拟线程实现的,在一个系统里面也许客户端这时真是要向服务器发起写入数据,也可能要读取数据,也可能才连接上服务器,服务器怎么来区别了,就使用这些常量来判断当前键的状态来进行操作