我正在学习Java,希望能够实现一个简单的联网四子棋游戏和聊天功能。
我想要我的网络逻辑是非阻塞的,经过研究后,我发现SocketChannel符合我的需求。
然而,仍然让我感到困惑的是SocketChannels中缺少回调函数,这与C#中的实现方式不同。
我的问题是:如何将接收到的数据传递到聊天或游戏窗口(JFrame)中?
希望能够得到一些指导。
我正在学习Java,希望能够实现一个简单的联网四子棋游戏和聊天功能。
我想要我的网络逻辑是非阻塞的,经过研究后,我发现SocketChannel符合我的需求。
然而,仍然让我感到困惑的是SocketChannels中缺少回调函数,这与C#中的实现方式不同。
我的问题是:如何将接收到的数据传递到聊天或游戏窗口(JFrame)中?
希望能够得到一些指导。
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(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 对象,然后调用 SocketChannel 的 read(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);
}
}