2010-04-21 19 views
5

我想学习Java。我想实现一个简单的网络连接4游戏以及聊天功能。Java ServerSocketChannel SocketChannel(回调)

我想我的网络逻辑是非阻塞的,所以经过多番研究后,我发现SocketChannel就是我在重新调整我的需求之后。

还没有意义的是SocketChannel中缺少CallBack函数..就像在C#中发现的一样。

我现在的查询是:如何将收到的数据传递给聊天或游戏窗体(JFrame)?

一些指导是最受欢迎的。

+0

我建议你使用多线程而不是非阻塞I/O。 – 2010-04-21 18:46:34

回答

13

您需要使用选择器。首先创建一个选择接收的事件:

Selector selector = Selector.open() 

然后,你需要注册与选择的的ServerSocketChannel:

SelectionKey acceptKey = server.register(selector, SelectionKey.OP_ACCEPT); 

然后,你需要使用选择,因为他们进来处理事件(你可以认为这是该过程的“回调”的一部分:

while(true){ 
    //how many channel keys are available 
    int available = selector.select(); 
    //select is blocking, but should only return if available is >0, this is more of a sanity check 
    if(available == 0) continue; 

    Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); 
    while(keys.hasNext()){ 
    SelectionKey key = keys.next(); 
    keys.remove(); 
    //someone is trying to connect to the server socket 
    if(key.isAcceptable()) doAccept(key); 
    //someone is sending us data 
    else if(key.isReadable()) doRead(key); 
    //we are trying to (and can) send data 
    else if(key.isWritable()) doWrite(key); 
} 

肉将在doAccept(),doRead(),和doWrite()对于接受键选择键将包含INF。 ormation来创建新的Socket。

doAccept(SelectionKey key){ 

//create the new socket 
SocketChannel socket = ((ServerSocketChannel)key.channel()).accept(); 
//make it non-blocking as well 
socket.configureBlocking(false); 

... 
//here you would likely have some code to init your game objects/communication protocol, etc. and generate an identifier object (used below). 
//and be able to find the socket created above 
... 

//Since it is non blocking it needs a selector as well, and we register for both read and write events 
SelectionKey socketKey = socket.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE); 
// so we can identify the events as they come in 
socketKey.attach(someSocketIndentifier); 
} 

最后一行添加了一些对象的键,以便从选择接收的事件可以归结为一个连接(例如,它可能是在你的游戏玩家)。所以现在你可以接受新的连接,你只需要读写。

doRead(SelectionKey key){ 
    //here we retrieve the key we attached earlier, so we now what to do/wheer the data is coming from 
    MyIdentifierType myIdentifier = (MyIdentifierType)key.attachment(); 
    //This is then used to get back to the SocketChannel and Read the Data 
    myIdentifier.readTheData(); 
} 

同样写

doWrite(SelectionKey key){ 
    //here we retrieve the key we attached earlier, so we now what to do/wheer the data is coming from 
    MyIdentifierType myIdentifier = (MyIdentifierType)key.attachment(); 
    //This is then used to get back to the SocketChannel and Read the Data 
    myIdentifier.getSocketHandler().writePendingData(); 
} 

阅读是相当简单的,你只需要创建一个字节缓冲区,然后调用SocketChannels读取(字节缓冲区)(及其变种或一个),准备好这些数据上该频道直到它空了。

写作是有点棘手,你通常会希望缓冲要写入的数据,直到你收到写事件:

class MyNetworkClass{ 
    ByteBuffer writeBuffer = ByteBuffer.allocate(1024); 
    SocketChannel commchannel; //from the server accept processing 

    ... 

    public void write(byte[] data){ 
    //here the class writeBuffer object is filled with the data 
    //but it isn't actually sent over the socket 
    ... 
    } 

    public void writePendingData(){ 
    //here actually write the data to the socket 
    commchannel.write(writeBuffer); 
    } 
} 

请注意,您将需要适当的代码来管理类的缓冲事件变满了,或者如果缓冲区中的数据没有全部写入套接字,则可以在写挂起方法中适当修改它,以及在此过程中可能抛出的各种异常。希望这有助于你开始。

+0

这一直非常有用,我现在更了解这个过程。 – iTEgg 2010-04-21 19:27:01

相关问题