- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我编写了一个应用程序,它通过 TCP 和 SocketChannel 连接到服务器但我有两个问题:
知道出了什么问题吗?
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SocketSelectorWorker extends Thread {
private static final transient Logger log = LoggerFactory.getLogger(SocketSelectorWorker.class);
private ExecutorService executorService = Executors.newFixedThreadPool(3);
private final Queue<byte[]> messages;
private Selector selector;
public SocketSelectorWorker(Queue messages, Selector selector) {
super();
this.selector = selector;
this.session = session;
this.messages = messages;
}
@Override
public void run() {
super.run();
while (isConnectionAlive()) {
try {
// Wait for an event
selector.select();
} catch (IOException e) {
log.error("Selector error: {}", e.toString());
log.debug("Stacktrace: ", e);
session.closeConnection();
break;
}
handleSelectorkeys(selector.selectedKeys());
}
executorService.shutdown();
log.debug("worker stopped");
}
private void handleSelectorkeys(Set<SelectionKey> selectedKeys) {
for (SelectionKey selKey : selector.selectedKeys()) {
selector.selectedKeys().remove(selKey);
try {
processSelectionKey(selKey);
} catch (IOException e) {
// Handle error with channel and unregister
selKey.cancel();
log.error("Selector error: {}", e.toString());
log.debug("Stacktrace: ", e);
}
}
}
public void processSelectionKey(SelectionKey selKey) throws IOException {
// Since the ready operations are cumulative,
// need to check readiness for each operation
if (selKey.isValid() && selKey.isConnectable()) {
log.debug("connectable");
// Get channel with connection request
SocketChannel sChannel = (SocketChannel) selKey.channel();
boolean success = sChannel.finishConnect();
if (!success) {
// An error occurred; handle it
log.error("Error on finish");
// Unregister the channel with this selector
selKey.cancel();
}
}
if (selKey.isValid() && selKey.isReadable()) {
log.debug("readable");
readMessage(selKey);
}
if (selKey.isValid() && selKey.isWritable()) {
log.debug("writable");
writeMessage(selKey);
}
if (selKey.isValid() && selKey.isAcceptable()) {
log.debug("Acceptable");
}
}
private void writeMessage(SelectionKey selKey) throws IOException {
byte[] message = messages.poll();
if (message == null) {
return;
}
// Get channel that's ready for more bytes
SocketChannel socketChannel = (SocketChannel) selKey.channel();
// See Writing to a SocketChannel
// Create a direct buffer to get bytes from socket.
// Direct buffers should be long-lived and be reused as much as
// possible.
ByteBuffer buf = ByteBuffer.allocateDirect(1024);// .allocateDirect(toSend.getBytes().length);
// try {
// Fill the buffer with the bytes to write;
// see Putting Bytes into a ByteBuffer
// buf.put((byte)0xFF);
buf.clear();
buf.put(new byte[] { 0x02 });
buf.put(message);
buf.put(new byte[] { 0x03 });
// Prepare the buffer for reading by the socket
buf.flip();
// Write bytes
int numBytesWritten = socketChannel.write(buf);
log.debug("Written: {}", numBytesWritten);
while (buf.hasRemaining()) {
numBytesWritten = socketChannel.write(buf);
log.debug("Written remining: {}", numBytesWritten);
}
}
private void readMessage(SelectionKey selKey) throws IOException {
// Get channel with bytes to read
SocketChannel socketChannel = (SocketChannel) selKey.channel();
// See Reading from a SocketChannel
// Create a direct buffer to get bytes from socket.
// Direct buffers should be long-lived and be reused as much as
// possible.
ByteBuffer buf = ByteBuffer.allocateDirect(2048);
Charset charset = Charset.forName("UTF-8");// Charset.forName("ISO-8859-1");
CharsetDecoder decoder = charset.newDecoder();
// try {
// Clear the buffer and read bytes from socket
buf.clear();
int numBytesRead = socketChannel.read(buf);
if (numBytesRead == -1) {
// No more bytes can be read from the channel
// socketChannel.close();
return;
}
log.debug("Read bytes: {}", numBytesRead);
// To read the bytes, flip the buffer
buf.flip();
String result = decoder.decode(buf).toString();
log.debug("Read string: {}", result);
//processMessage(result.getBytes());
}
}
最佳答案
您没有正确处理选择键。迭代时必须通过迭代器删除,而不是通过集合。这意味着您无法使用增强的 for 循环。可能您正在跳过按键。
当您从 read()
获得 -1 时,您必须关闭 channel 。
当您收到 IOException
时,仅取消 key 是不够的。您应该关闭 channel ,NB 会自动取消它们的 key 。
关于java - SocketChannel 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28174128/
我知道 SocketChannel 通过在调用 read() 后接收到“-1”来“通知”有序关闭的连接。 但是它如何通知我有关无序关闭的连接呢? (作为整个基于 NIO 的服务器的一部分,使用选择器和
我尝试在两个不同的线程(Android API 级别 25)中同时使用 SocketChannel.write 和 SocketChannel.read。 我将 SocketChannel 配置为阻塞
根据文档,我可以这样做: SocketChannel mySocketChannel = new SocketChannel(SelectorProvider.provider()); 根据 JDK,
我正在用Java开发多线程非阻塞tcp服务器和客户端。我在服务器意识到客户端套接字已关闭时遇到问题。对他来说一切都是开放的。这是代码和我的代码的输出: 服务器: /* * To change thi
我正在编写一个聊天室服务器,它从聊天客户端获取消息并将该消息广播给所有用户。这是《Java 网络编程简介:Java 7 兼容》一书中的一个练习,我正在自学 Java 网络基础知识。我按照书中代码的示例
我构建了一个客户端(SocketChannel),它正在获取大消息(每条消息的大小约为 1MB-2MB)。我怎样才能收到消息?我正在使用选择器。当键为Readable时,我想读取接收消息的所有数据包。
我正在尝试通过 SocketChannel 发送数据(400016 字节)。由于某种原因,并未发送所有数据。 (我希望看到所有 400016 字节都将被发送) 代码如下:公共(public) bool
我编写了一个应用程序,它通过 TCP 和 SocketChannel 连接到服务器但我有两个问题: 第一个是次要的 - 有时出于某种未知的原因我会发送串联的消息, 第二个至关重要 - 应用会定期停止发
假设我们有一个打开的 SocketChannel。在终止应用程序之前明确关闭它很重要吗?换句话说,如果我们不这样做,是否存在留下未关闭的系统资源的风险? 最佳答案 假设您的操作系统是一个现代的多用户操
这是我的代码。从测试服务器,我尝试通过输出流发送数据并从测试客户端接收数据。我使用 SocketChannel 是因为我需要客户端同时监听 3 个端口。目前,我只想从一个套接字读取数据。但是它似乎没有
我再次遇到 Android 套接字编程方面的问题。我的问题是 Selector.select() 返回零,表示没有准备好写入的 SocketChannels。同样的代码同样适用于普通的 Java,但不
我正在使用套接字 channel 和 NIO 概念从客户端读取数据。 Socket Channel 如何知道文件读取完成? ByteBuffer byteBuffer = ByteBuffer.all
我创建了一个到远程服务器的 SocketChannel,以便在 Tomcat 上发送和接收消息。为了从远程计算机接收消息,我使用了一个专用于任务的线程(只有这个线程将从套接字读取,没有其他线程)。 当
我有一个正在运行的套接字,使用选择器。我正在尝试检查我的套接字是否已连接到服务器。 Boolean connected = _channel.isConnected(); 它总是返回真。我关闭了计算机
我想使用 SocketChannel 并为其读/写方法设置超时。我试过为拥有我的 SocketChannel 的套接字设置超时,如下所示: channel.socket().setSoTimeout(
我正在努力理解 SocketChannels , 和 NIO一般来说。我知道如何使用常规套接字以及如何制作一个简单的每个客户端线程服务器(使用常规阻塞套接字)。 所以我的问题: 什么是 SocketC
我刚刚写了一些 NIO 代码,想知道如何对我的实现进行压力测试 SocketChannel.write(ByteBuffer) 无法写入整个字节缓冲区 SocketChannel.read(ByteB
我们有一个带有 https 的服务器,它在端口 443 上运行。我想从服务器读取字节。我正在使用以下代码。 private void openAndConfigureChannel(Selector
这个问题已经有答案了: when I use nio, serverSocket.accept() throws IllegalBlockingModeException (3 个回答) 已关闭 4
我的应用程序有一个队列,其中包含“传出网络数据包”(带有 ByteBuffer 和 SocketChannel 的 POJO),由将数据写入的单个线程使用SocketChannel。 我这样做是为了保
我是一名优秀的程序员,十分优秀!