import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
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 TCP { ServerSocketChannel socketChannel;
Selector selector;
int port = 8778;
String[] opsName=new String[17];
public TCP(){
opsName[SelectionKey.OP_ACCEPT]="OP_ACCEPT";
opsName[SelectionKey.OP_CONNECT]="OP_CONNECT";
opsName[SelectionKey.OP_READ]="OP_READ";
opsName[SelectionKey.OP_WRITE]="OP_WRITE";
try {
socketChannel=ServerSocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.socket().setReuseAddress(true);
socketChannel.socket().bind(new InetSocketAddress(port));
selector=Selector.open();
System.out.println(socketChannel.hashCode());

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void start(){
try {
socketChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (ClosedChannelException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.println("server start port "+port);
while(true){

int n;
try {
System.out.print("wait...");
n = selector.select(60000);
System.out.println(n);
if(n<=0)continue;

Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while(it.hasNext()){
SelectionKey key = it.next();
it.remove();
System.out.println("key:"+opsName[key.interestOps()]+","+key.channel().hashCode());
if(key.isReadable()){
System.out.println(key.hashCode()+" isReadable");
socketChannel.accept().register(selector, SelectionKey.OP_READ);
//问题2:socketChannel 与 (SocketChannel)socketChannel.accept() 这两个channel什么区别
}

else if(key.isAcceptable()){
//问题1:当一个客户端连接进来时,为什么这句话会一直重复地打印
System.out.println(key.hashCode()+" accepted");
}

}

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
} public static void main(String[] args) {
TCP tcp = new TCP();
tcp.start();
}
}

解决方案 »

  1.   

        //问题1:当一个客户端连接进来时,为什么这句话会一直重复地打印
    要remove掉,API里面有说明,待会再贴给你看
     //问题2:socketChannel 与 (SocketChannel)socketChannel.accept() 这两个channel什么区别
    一个是ServerSocket用来连接客户端的,一个是已经连接上了客户端的需要read或write的
      

  2.   

    我有remove的,你看这:
     while(it.hasNext()){
                        SelectionKey key = it.next();
                        it.remove();...
      

  3.   

     //问题2:socketChannel 与 (SocketChannel)socketChannel.accept() 这两个channel什么区别这里的socketChannel是服务端ServerSocketChannel,而socketChannel.accept()这个是服务端接受到的SocketChannel。就像ServerSocket的socket = server.accept()这里也是ServerSocket接受到的客户端的Socket。 //问题1:当一个客户端连接进来时,为什么这句话会一直重复地打印
    这里肯定了,你判断的条件是 else if(key.isAcceptable()),也就是如果客户端连接来了就会打印。连接了后你应该再把服务端变成可读的,但是你什么都没写。也就是一直只是可接受的。所以其他的if没有执行。可以看下面代码:  public class server {
    ServerSocketChannel ssc; public void start() {
    try {
    Selector selector = Selector.open();
    ServerSocketChannel ssc = ServerSocketChannel.open();
    ssc.configureBlocking(false);
    ServerSocket ss = ssc.socket();
    InetSocketAddress address = new InetSocketAddress(55555);
    ss.bind(address);
    ssc.register(selector, SelectionKey.OP_ACCEPT);
    System.out.println("端口注册完毕!");
    while (true) {
    selector.select();
    Set selectionKeys = selector.selectedKeys();
    Iterator iter = selectionKeys.iterator();
    ByteBuffer echoBuffer = ByteBuffer.allocate(20);
    SocketChannel sc;
    while (iter.hasNext()) {
    SelectionKey key =(SelectionKey) iter.next();
    if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
    ServerSocketChannel subssc = (ServerSocketChannel) key
    .channel();
    sc = subssc.accept();
    sc.configureBlocking(false);
    sc.register(selector, SelectionKey.OP_READ);
    iter.remove();
    System.out.println("有新连接:" + sc);
    } else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
    sc = (SocketChannel) key.channel();
    while (true) {
    echoBuffer.clear();
    int a;
    try {
    a = sc.read(echoBuffer);
    } catch (Exception e) {
    e.printStackTrace();
    break;
    }
    if (a == -1)
    break;
    if (a > 0) {
    byte[] b = echoBuffer.array();
    System.out.println("接收数据: " + new String(b));
    echoBuffer.flip();
    sc.write(echoBuffer);
    System.out.println("返回数据: " + new String(b));
    }
    }
    sc.close();
    System.out.println("连接结束");
    System.out.println("=============================");
    iter.remove();
    }
    }
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    }
    public static void main(String[] args){
    server s = new server();
    s.start();
    }
    }
      

  4.   

       socketChannel.accept().register(selector, SelectionKey.OP_READ);这句话丢到acceptable的if条件里面
      

  5.   

    好像还是有问题,有些没弄明白了
    首先进来acceptable,但是你又没注册其他的key,然后都remove了再哪来key进入,迭代数量应该为0了吧
      

  6.   

    我晕没仔细看你代码,你这代码整个逻辑都有问题
    你在key.isAcceptable()里面没有做任何操作,实际上就是你根本就没有建立连接
    该channel一直处于就绪状态,即使remove掉把selectedKey里面删除了,keys里面还是存在
    下次select发现状态还是就绪就继续选择出来
    你应该在key.isAcceptable()里面accept,然后将返回的socketChannel置为可读key