gpt4 book ai didi

Java ServerSocketChannel SocketChannel(回调)

转载 作者:搜寻专家 更新时间:2023-10-31 08:18:25 27 4
gpt4 key购买 nike

我正在努力学习 Java。我想实现一个简单的联网 connect 4 游戏以及聊天功能。

我希望我的网络逻辑是非阻塞的,所以经过大量研究后,我发现 SocketChannel 正是我重新调整需求后的样子。

仍然没有意义的是 SocketChannels 中缺少回调函数。就像在 C# 中发现的那样。

我这次的问题是:如何将接收到的数据传递给聊天或游戏窗体(JFrame)?

欢迎提供一些指导。

最佳答案

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

Selector selector = Selector.open()

然后需要向选择器注册ServerSocketChannel:

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

然后您需要使用 Selector 在事件传入时对其进行处理(您可以将其视为流程的“回调”部分:

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()。对于接受键,选择键将包含创建新套接字的信息。

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 read(ByteBuffer)(或其变体之一)以在 channel 上准备好数据,直到它为空。

写入有点棘手,因为您通常希望缓冲要写入的数据,直到收到写入事件:

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);
}
}

请注意,如果缓冲区已满,您将需要适当的代码来管理类中的缓冲区,或者如果缓冲区中的所有数据并未写入套接字,则需要在写入挂起方法中对其进行适当修改,以及在此过程中可能抛出的各种异常。希望这有助于您入门。

关于Java ServerSocketChannel SocketChannel(回调),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2685534/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com