简体   繁体   English

即使我注册了一个准备从另一个线程读取的通道,Selector.select() 也没有被解除阻塞

[英]Selector.select() not being unblocked even after I register a channel ready to read from another thread

I am creating a server to handle many different connections at the same time.我正在创建一个服务器来同时处理许多不同的连接。 I create two Selector s, on for the serverSocketChannel to accept and then the other for the connections to read data.我创建了两个Selector ,一个用于 serverSocketChannel accept ,另一个用于连接读取数据。

The one selector successfully gets past the blocking select() function to accept the new connection.一个选择器成功通过阻塞select() function 以接受新连接。 Then the goal is to register that SocketChannel that was accepted with the other selector that is currently blocked by it's select() function so that I can read the data when I need to.然后目标是注册被当前被它的select() function 阻止的另一个选择器接受的 SocketChannel,以便我可以在需要时读取数据。

Everything seems to be set up correctly, but even after sending data, I am not getting past the other selector's select() function.一切似乎都设置正确,但即使在发送数据之后,我也没有通过其他选择器的select() function。

Here is my server file:这是我的服务器文件:

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;
import java.util.TreeSet;

public class Server implements Runnable
{
    
    public Thread threadAccept;
    public Thread threadRead;
    
    protected ServerSocketChannel serverSocket;
    
    protected Selector selectorAccept;
    protected Selector selectorIO;

    protected Set<Connection> connections;
    
    private ByteBuffer buffer;
    
    public Server()
    {
        try
        {
            selectorAccept = Selector.open();
            selectorIO = Selector.open();
            
            serverSocket = ServerSocketChannel.open();
            serverSocket.configureBlocking(false);
            
            InetSocketAddress hostAddress = new InetSocketAddress("localhost",4444);
            serverSocket.bind(hostAddress);
            int ops = serverSocket.validOps();
            SelectionKey selectKey = serverSocket.register(selectorAccept, ops);
            
            
            threadAccept = new Thread(this);
            threadAccept.start();
            
            threadRead = new Thread(this);
            threadRead.start();
            
        }
        catch(Exception e)
        {
            System.out.println("Error "+e);
        }
    }
    
    public void run()
    {
        if(Thread.currentThread() == threadAccept)
        {
            acceptNewConnections();
        }
        else if(Thread.currentThread() == threadRead)
        {
            readData();
        }
    }
    
    private void acceptNewConnections()
    {
        int numberOfKeys = 0;
        
        while(true)
        {
            try
            {
                numberOfKeys = selectorAccept.select();
                Set<SelectionKey> keys = selectorAccept.selectedKeys();
                Iterator<SelectionKey> itr = keys.iterator();
                
                while(itr.hasNext())
                {
                    SelectionKey key = itr.next();
                    if(key.isAcceptable())
                    {
                        SocketChannel client = serverSocket.accept();
                        client.configureBlocking(false);
                        client.register(selectorIO, SelectionKey.OP_READ);
                        System.out.println("New connection");
                    }
                }
            }
            catch(Exception e)
            {
                System.out.println(e);
            }
        }
    }
    
    public void readData()
    {
        int numberOfKeys = 0;
        ByteBuffer buffer = ByteBuffer.allocate(256);
        
        while(true)
        {
            try
            {
                System.out.println("About to block on IO selector");
                numberOfKeys = selectorIO.select();
                System.out.println("I NEVER GET HERE");
                
                Set<SelectionKey> keys = selectorIO.selectedKeys();
                Iterator<SelectionKey> itr = keys.iterator();
                
                while(itr.hasNext())
                {
                    SelectionKey key = itr.next();
                    if(key.isReadable())
                    {
                        SocketChannel channel = (SocketChannel)key.channel();
                        channel.read(buffer);
                        
                        String s = buffer.toString();
                        System.out.println(s);
                    }
                }
            }
            catch(Exception e)
            {
                System.out.println(e);
            }
        }
    }
    
    
}

And here is my main class to kick the server off and also create a client.这是我的主要 class,用于启动服务器并创建客户端。

import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

public class Main
{
    public static void main(String[] args)
    {
        Server s = new Server();
        
        
        
        Thread t = new Thread(new Runnable() {
            public void run()
            {
                try
                {
                    Socket s = new Socket("localhost", 4444);
                    byte[] data = "hello".getBytes();
                    s.getOutputStream().write(data);
                    s.getOutputStream().flush();
                } catch (UnknownHostException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });
        
        t.start();
    }
}

My guess is that a wakeup would be sufficient我的猜测是唤醒就足够了

client.register(selectorIO, SelectionKey.OP_READ);
selectorIO.wakeup();

Or just execute a task on the client thread where it registers the client on the same selectorIO it is waiting for.或者只是在客户端线程上执行一个任务,它将客户端注册到它正在等待的同一个 selectorIO 上。 So the client thread should also check for a task queue as part of its loop (eg ConcurrentLinkedQueue) and call a selectorIO.wakup after placing the task in the task queue.因此,客户端线程还应检查任务队列作为其循环的一部分(例如 ConcurrentLinkedQueue),并在将任务放入任务队列后调用 selectorIO.wakup。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM