- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在努力学习 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/
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve th
我有以下代码: Selector socketSelector = SelectorProvider.provider().openSelector(); ServerSocketChannel s
当用户单击“连接”按钮时,我的 SwingWorker 的 doInBackground() 创建(并向 OP_ACCEPT 注册)一个新的 ServerSocketChannel。 当客户端 isA
当 ServerSocketChannel 在非阻塞模式下使用并在选择器中注册时,以下 Channel.close() 调用不会立即关闭套接字,并且它在 LISTENING 状态下的 netstat
对 ServerSocketChannel.open() 的调用从未返回。我们使用的是jdk1.8.0_144。 堆栈跟踪显示它永远停留在 ServerSocketChannelImpl 类初始化中。
选择器阻塞 ServerSocketChannel 的用例是什么时候?通常,选择器如何处理阻塞 channel ? 最佳答案 这是来自 SelectableChannel javadoc : A ch
我正在努力学习 Java。我想实现一个简单的联网 connect 4 游戏以及聊天功能。 我希望我的网络逻辑是非阻塞的,所以经过大量研究后,我发现 SocketChannel 正是我重新调整需求后的样
为什么我们必须创建一个InetSocketAddress对象? 但是对于ServerSocket,我们只需使用int来输入端口号 示例: try( ServerSocketChanne
我已经开始开发一个预先开发的 Java 应用程序,其中处理 java 套接字。该项目的主要概念是在java套接字服务器上从客户端获取数据并对其进行处理。 该项目是使用 Java NIO ServerS
这是一个非常基本的问题,但我在任何地方都找不到明确的答案: 当我 accept()来自 ServerSocketChannel 的连接,我是否保证返回的 SocketChannel 是“connect
我有一个java.nio.channels.ServerSocketChannel,我初始化如下: while(true) { ServerSocketChannel channel = Se
我的 Android 应用程序中有服务器线程,当用户决定关闭它时需要正确处理它。我选择接受()客户端的非阻塞 ServerSocketChannel。 并得到了这个 public class Sock
我有一个 Android 设备,它将运行一个服务器,其他 Android 设备(客户端)将连接到该服务器。我在非阻塞模式下使用 SocketChannel 和 ServerSocketChannel。
HTML5可以和Java Serversocketchannel通信吗?如果可能,任何人都可以告诉我详细信息。 提前致谢。 最佳答案 我假设您谈论的是 WebSockets 而不是其他协议(proto
我在守护线程上有一个计时器,它不断地将数据写入 SocketChannel 。在主类中,我没有此套接字 channel 的对象引用,但我有 ServerSocket 的引用该套接字 channel 连
我有一个应用程序,我需要在其中使用 ServerSocketChannel 和 SocketChannel,但是 SSLContext 给了我 ServerSocketFactory它提供 Serve
我正在用 Java 开发一个小组对话服务器,我目前正在破解网络代码,但似乎我无法在阻塞 I/O 操作上设置正确的超时:我可能被某些 Java 攻击了怪异(或者,简单地说,我误解了 javadoc)。
我不明白 NIO 是如何工作的。这是一个示例代码: // Create the server socket channel ServerSocketChannel server = ServerSoc
我有一个 ServerSocketChannel 和一个 Socket.ServerSocket 绑定(bind)在端口 8888 上。Socket连接到ServerSocket并发送数据。如果我只关
当我将 selector.select() 注册到 SocketChannel 并在单独的线程中关闭 SocketChannel 的对等体时,selector.select() 返回,并且设置了该 c
我是一名优秀的程序员,十分优秀!