java socket回调_Java ServerSocketChannel SocketChannel(回调)

本文介绍了如何在Java中使用Selector和SocketChannel实现回调机制,通过注册ServerSocketChannel并监听OP_ACCEPT、OP_READ和OP_WRITE事件,实现非阻塞I/O操作。在doAccept、doRead和doWrite方法中处理相应的事件,以处理客户端连接、读取数据和发送数据。同时强调了读写操作的注意事项,如数据缓冲和异常处理。
摘要由CSDN通过智能技术生成

您需要使用选择器.首先创建一个Selector来接收事件:

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 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()中.对于接受键,选择键将包含用于创建新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();

}

读取是相当简单的,您只需创建一个ByteBuffer,然后调用SocketChannels读取(ByteBuffer)(或其中一个变体),以便在通道上准备好数据,直到它为空.

写入有点棘手,因为在收到写入事件之前,通常需要缓冲要写入的数据:

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值