仅通过一个 SocketChannel 发送多条消息

2024-03-26

读完本教程后:http://rox-xmlrpc.sourceforge.net/niotut/ http://rox-xmlrpc.sourceforge.net/niotut/(这是关于编写非阻塞服务器和客户端,我阅读了NIO部分,跳过了SSL部分),现在我正在尝试重写我自己的客户端,但是在尝试编辑客户端代码时遇到了问题。

首先,我想让你看一下教程的客户端代码,它包含2个文件:

  • RspHandler.java:http://rox-xmlrpc.sourceforge.net/niotut/src/RspHandler.java http://rox-xmlrpc.sourceforge.net/niotut/src/RspHandler.java

  • NIOClient.java:http://rox-xmlrpc.sourceforge.net/niotut/src/NioClient.java http://rox-xmlrpc.sourceforge.net/niotut/src/NioClient.java

但我编辑了 NIOClient.java 一点main函数解释我的问题如下:

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.*;

public class NIOClient implements Runnable {
// The host:port combination to connect to
private InetAddress hostAddress;
private int port;

// The selector we'll be monitoring
private Selector selector;

// The buffer into which we'll read data when it's available
private ByteBuffer readBuffer = ByteBuffer.allocate(8192);

// A list of PendingChange instances
private List pendingChanges = new LinkedList();

// Maps a SocketChannel to a list of ByteBuffer instances
private Map pendingData = new HashMap();

// Maps a SocketChannel to a RspHandler
private Map rspHandlers = Collections.synchronizedMap(new HashMap());

public NIOClient(InetAddress hostAddress, int port) throws IOException {
    this.hostAddress = hostAddress;
    this.port = port;
    this.selector = this.initSelector();
}

public void send(byte[] data, RspHandler handler) throws IOException {
    // Start a new connection
    SocketChannel socket = this.initiateConnection();

    // Register the response handler
    this.rspHandlers.put(socket, handler);

    // And queue the data we want written
    synchronized (this.pendingData) {
        List queue = (List) this.pendingData.get(socket);
        if (queue == null) {
            queue = new ArrayList();
            this.pendingData.put(socket, queue);
        }
        queue.add(ByteBuffer.wrap(data));
    }

    // Finally, wake up our selecting thread so it can make the required changes
    this.selector.wakeup();
}

public void run() {
    while (true) {
        try {
            // Process any pending changes
            synchronized (this.pendingChanges) {
                Iterator changes = this.pendingChanges.iterator();
                while (changes.hasNext()) {
                    ChangeRequest change = (ChangeRequest) changes.next();
                    switch (change.type) {
                    case ChangeRequest.CHANGEOPS:
                        SelectionKey key = change.socket.keyFor(this.selector);
                        key.interestOps(change.ops);
                        break;
                    case ChangeRequest.REGISTER:
                        change.socket.register(this.selector, change.ops);
                        break;
                    }
                }
                this.pendingChanges.clear();
            }

            // Wait for an event one of the registered channels
            this.selector.select();

            // Iterate over the set of keys for which events are available
            Iterator selectedKeys = this.selector.selectedKeys().iterator();
            while (selectedKeys.hasNext()) {
                SelectionKey key = (SelectionKey) selectedKeys.next();
                selectedKeys.remove();

                if (!key.isValid()) {
                    continue;
                }

                // Check what event is available and deal with it
                if (key.isConnectable()) {
                    this.finishConnection(key);
                } else if (key.isReadable()) {
                    this.read(key);
                } else if (key.isWritable()) {
                    this.write(key);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private void read(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    // Clear out our read buffer so it's ready for new data
    this.readBuffer.clear();

    // Attempt to read off the channel
    int numRead;
    try {
        numRead = socketChannel.read(this.readBuffer);
    } catch (IOException e) {
        // The remote forcibly closed the connection, cancel
        // the selection key and close the channel.
        key.cancel();
        socketChannel.close();
        return;
    }

    if (numRead == -1) {
        // Remote entity shut the socket down cleanly. Do the
        // same from our end and cancel the channel.
        key.channel().close();
        key.cancel();
        return;
    }

    // Handle the response
    this.handleResponse(socketChannel, this.readBuffer.array(), numRead);
}

private void handleResponse(SocketChannel socketChannel, byte[] data, int numRead) throws IOException {
    // Make a correctly sized copy of the data before handing it
    // to the client
    byte[] rspData = new byte[numRead];
    System.arraycopy(data, 0, rspData, 0, numRead);

    // Look up the handler for this channel
    RspHandler handler = (RspHandler) this.rspHandlers.get(socketChannel);

    // And pass the response to it
    if (handler.handleResponse(rspData)) {
        // The handler has seen enough, close the connection
        socketChannel.close();
        socketChannel.keyFor(this.selector).cancel();
    }
}

private void write(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    synchronized (this.pendingData) {
        List queue = (List) this.pendingData.get(socketChannel);

        // Write until there's not more data ...
        while (!queue.isEmpty()) {
            ByteBuffer buf = (ByteBuffer) queue.get(0);
            socketChannel.write(buf);
            if (buf.remaining() > 0) {
                // ... or the socket's buffer fills up
                break;
            }
            queue.remove(0);
        }

        if (queue.isEmpty()) {
            // We wrote away all data, so we're no longer interested
            // in writing on this socket. Switch back to waiting for
            // data.
            key.interestOps(SelectionKey.OP_READ);
        }
    }
}

private void finishConnection(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    // Finish the connection. If the connection operation failed
    // this will raise an IOException.
    try {
        socketChannel.finishConnect();
    } catch (IOException e) {
        // Cancel the channel's registration with our selector
        System.out.println(e);
        key.cancel();
        return;
    }

    // Register an interest in writing on this channel
    key.interestOps(SelectionKey.OP_WRITE);
}

private SocketChannel initiateConnection() throws IOException {
    // Create a non-blocking socket channel
    SocketChannel socketChannel = SocketChannel.open();
    socketChannel.configureBlocking(false);

    // Kick off connection establishment
    socketChannel.connect(new InetSocketAddress(this.hostAddress, this.port));

    // Queue a channel registration since the caller is not the 
    // selecting thread. As part of the registration we'll register
    // an interest in connection events. These are raised when a channel
    // is ready to complete connection establishment.
    synchronized(this.pendingChanges) {
        this.pendingChanges.add(new ChangeRequest(socketChannel, ChangeRequest.REGISTER, SelectionKey.OP_CONNECT));
    }

    return socketChannel;
}

private Selector initSelector() throws IOException {
    // Create a new selector
    return SelectorProvider.provider().openSelector();
}

public static void main(String[] args) {
    try {
        NIOClient client = new NIOClient(
                InetAddress.getByName("127.0.0.1"), 9090);
        Thread t = new Thread(client);
        t.setDaemon(true);
        t.start();

        // 1st
        client.send("hehe|||".getBytes());
        System.out.println("SEND: " + "hehe|||");
        handler.waitForResponse();

        System.out.println("------------");

        // 2nd
        client.send(("hehe|||" + " 2").getBytes());
        System.out.println("SEND: " + "hehe|||" + " 2");
        handler.waitForResponse();

    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

我编辑的客户端只做了一件简单的事情,就是向服务器发送消息,然后从服务器接收回显消息。当然,上面的代码运行良好。它发送了 2 条消息,然后正确地收到了它们。

但我不希望在上述客户端中出现的是:send函数调用此代码:

    // Start a new connection
    SocketChannel socket = this.initiateConnection();

这意味着每一个有区别的消息都将与每个有区别的新SocketChannel相对应,但现在我只想使用一个SocketChannel来发送许多消息,所以我像下面的代码一样更改客户端:

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.*;

public class MyClient implements Runnable {
// The host:port combination to connect to
private InetAddress hostAddress;
private int port;

// The selector we'll be monitoring
private Selector selector;

// The buffer into which we'll read data when it's available
private ByteBuffer readBuffer = ByteBuffer.allocate(8);

// A list of PendingChange instances
private List pendingChanges = new LinkedList();

// Maps a SocketChannel to a list of ByteBuffer instances
private Map pendingData = new HashMap();

// Maps a SocketChannel to a RspHandler
private Map rspHandlers = Collections.synchronizedMap(new HashMap());


private SocketChannel socket;
private static MyResponseHandler handler;

public MyClient(InetAddress hostAddress, int port) throws IOException {
    this.hostAddress = hostAddress;
    this.port = port;
    this.selector = this.initSelector();

    // Start a new connection
    socket = this.initiateConnection();

    handler = new MyResponseHandler();
    // Register the response handler
    this.rspHandlers.put(socket, handler);      
}

public void send(byte[] data) throws IOException {

    // And queue the data we want written
    synchronized (this.pendingData) {
        List queue = (List) this.pendingData.get(socket);
        if (queue == null) {
            queue = new ArrayList();
            this.pendingData.put(socket, queue);
        }
        queue.add(ByteBuffer.wrap(data));
    }

    // Finally, wake up our selecting thread so it can make the required changes
    this.selector.wakeup();
}

public void run() {
    while (true) {
        try {
            // Process any pending changes
            synchronized (this.pendingChanges) {
                Iterator changes = this.pendingChanges.iterator();
                while (changes.hasNext()) {
                    ChangeRequest change = (ChangeRequest) changes.next();
                    switch (change.type) {
                    case ChangeRequest.CHANGEOPS:
                        SelectionKey key = change.socket.keyFor(this.selector);
                        key.interestOps(change.ops);
                        break;
                    case ChangeRequest.REGISTER:
                        change.socket.register(this.selector, change.ops);
                        break;
                    }
                }
                this.pendingChanges.clear();
            }

            // Wait for an event one of the registered channels
            this.selector.select();

            // Iterate over the set of keys for which events are available
            Iterator selectedKeys = this.selector.selectedKeys().iterator();
            while (selectedKeys.hasNext()) {
                SelectionKey key = (SelectionKey) selectedKeys.next();
                selectedKeys.remove();

                if (!key.isValid()) {
                    continue;
                }

                // Check what event is available and deal with it
                if (key.isConnectable()) {
                    this.finishConnection(key);
                } else if (key.isReadable()) {
                    this.read(key);
                } else if (key.isWritable()) {
                    this.write(key);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private void read(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    // Clear out our read buffer so it's ready for new data
    this.readBuffer.clear();

    // Attempt to read off the channel
    int numRead;
    try {
        numRead = socketChannel.read(this.readBuffer);
    } catch (IOException e) {
        // The remote forcibly closed the connection, cancel
        // the selection key and close the channel.
        key.cancel();
        socketChannel.close();
        return;
    }

    if (numRead == -1) {
        // Remote entity shut the socket down cleanly. Do the
        // same from our end and cancel the channel.
        key.channel().close();
        key.cancel();
        return;
    }

    // Handle the response
    this.handleResponse(socketChannel, this.readBuffer.array(), numRead);
}

private void handleResponse(SocketChannel socketChannel, byte[] data, int numRead) throws IOException {
    // Make a correctly sized copy of the data before handing it
    // to the client
    byte[] rspData = new byte[numRead];
    System.arraycopy(data, 0, rspData, 0, numRead);

    // Look up the handler for this channel
    MyResponseHandler handler = (MyResponseHandler) this.rspHandlers.get(socketChannel);

    // And pass the response to it
    if (handler.handleResponse(rspData)) {
        // The handler has seen enough, close the connection
        socketChannel.close();
        socketChannel.keyFor(this.selector).cancel();
    }
}

private void write(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    synchronized (this.pendingData) {
        List queue = (List) this.pendingData.get(socketChannel);

        // Write until there's not more data ...
        while (!queue.isEmpty()) {
            ByteBuffer buf = (ByteBuffer) queue.remove(0);
            socketChannel.write(buf);

            //-- DEBUG --
            System.out.println("===>>> socketChannel.write: " + new String(buf.array()));

            if (buf.remaining() > 0) {
                // ... or the socket's buffer fills up
                break;
            }
        }

        if (queue.isEmpty()) {
            // We wrote away all data, so we're no longer interested
            // in writing on this socket. Switch back to waiting for
            // data.
            key.interestOps(SelectionKey.OP_READ);
        }
    }
}

private void finishConnection(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    // Finish the connection. If the connection operation failed
    // this will raise an IOException.
    try {
        socketChannel.finishConnect();
    } catch (IOException e) {
        // Cancel the channel's registration with our selector
        System.out.println(e);
        key.cancel();
        return;
    }

    // Register an interest in writing on this channel
    key.interestOps(SelectionKey.OP_WRITE);
}

private SocketChannel initiateConnection() throws IOException {
    // Create a non-blocking socket channel
    SocketChannel socketChannel = SocketChannel.open();
    socketChannel.configureBlocking(false);

    // Kick off connection establishment
    socketChannel.connect(new InetSocketAddress(this.hostAddress, this.port));

    // Queue a channel registration since the caller is not the 
    // selecting thread. As part of the registration we'll register
    // an interest in connection events. These are raised when a channel
    // is ready to complete connection establishment.
    synchronized(this.pendingChanges) {
        this.pendingChanges.add(new ChangeRequest(socketChannel, ChangeRequest.REGISTER, SelectionKey.OP_CONNECT));
    }

    return socketChannel;
}

private Selector initSelector() throws IOException {
    // Create a new selector
    return SelectorProvider.provider().openSelector();
}

public static void main(String[] args) {
    try {
        MyClient client = new MyClient(
                InetAddress.getByName("127.0.0.1"), 9090);
        Thread t = new Thread(client);
        t.setDaemon(true);
        t.start();

        // 1st
        client.send("hehe|||".getBytes());
        System.out.println("SEND: " + "hehe|||");
        handler.waitForResponse();

        System.out.println("------------");

        // 2nd
        client.send(("hehe|||" + " 2").getBytes());
        System.out.println("SEND: " + "hehe|||" + " 2");
        handler.waitForResponse();

    } catch (Exception e) {
        e.printStackTrace();
    }
}
}

但是运行上面的客户端后,我只看到第一条消息被发送和接收回来,经过调试,我知道第二条消息没有发送,但我不知道为什么以及如何解决该问题。

有人知道答案吗?

感谢您阅读我很长的问题。


你从错误的地方开始。那篇文章有很多问题。所有这些待更改队列的内容都是一个巨大的、不必要的复杂化。只是wakeup()如果您需要从另一个线程注册/注销选择器(尽管为什么您需要这样做对我来说完全是个谜),并且您可以更改interestOps任何时候都以同样的方式完全可靠,即使他传播的关于不同实现的 FUD 曾经实现过。

这篇文章还有其他几个问题,表明作者并不真正知道自己在说什么。一个IOException并不一定意味着“远程强制关闭连接”。他的finishConnection()方法忽略返回值,如果为 false,则意味着连接仍处于挂起状态,因此它会注册超出OP_CONNECT过早地阶段。关闭通道会取消密钥,因此所有这些cancel()紧接在其之前或之后的调用close()调用是多余的,可以删除(尽管有些地方他取消了而不关闭,这也是错误的地方)。

Further:

在刚刚介绍的两种方法中,我们没有要求 OP_CONNECT 标志设置在套接字通道的选择键上。要是我们 我们会覆盖 OP_CONNECT 标志并且永远不会完成 联系。如果我们把它们结合起来,那么我们就会冒着试图写下去的风险 一个未连接的通道(或者至少必须处理这种情况)”

这完全是A级废话。设置 OP_CONNECT 两次,或者“然后组合它们”,无论这意味着什么,都不可能导致您“永远不会完成连接”或“尝试在未连接的通道上写入”。他似乎认为设置两次就可以清除它。

数据已经排队(否则我们不会建立一个 首先连接)。

一个奇怪且无法解释的假设。

如果您在 Oracle 论坛迁移后仍然可以找到它,我会仔细看看他引用的“驯服 NIO Circus”主题,而不是那种相当可疑的混乱。免责声明:其中一些是我写的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

仅通过一个 SocketChannel 发送多条消息 的相关文章

  • 当转义引号存在时,在外部引号或外部方括号中分割逗号

    是否可以按照以下条件拆分字符串 用 即逗号 分隔 在每个元素上 忽略第一个 和最后一个 内的逗号检查 在每个元素上 忽略第一个 和最后一个 内的逗号检查 e g String source to char DATE YYYY MM DD I
  • 非常大的 JTable、RowFilter 和额外负载

    我想请求澄清 RowFilter 的使用及其对性能的影响 我通过 include Entry 方法实现了一个过滤器 对于每一行 只需检查模型中其对应值是否设置了布尔标志 如果是 则返回 true 否则返回 false 现在 我拥有的 JTa
  • 使用 Spring boot CrudRepository 过滤数据

    我有一个简单的 REST 服务 可以使用 Spring boot 访问数据CrudRepository 该存储库已经实现了分页和排序功能 如下所示 public interface FlightRepository extends Crud
  • 我需要帮助理解 java 中 Timer 类的 ScheduleAtFixedRate 方法

    作为一个粉丝番茄工作法 http www pomodorotechnique com 我正在为自己制作一个倒计时器 以保证我完成作业 然而 这个特定的项目不是家庭作业 Stack 有很多关于使用计时器来控制用户输入之前的延迟等问题 但关于独
  • 让线程休眠的更好方法

    我一直在编写有关 Java 8 中 2D 图形的教程 当时 NetBeans 给了我一个提示 Thread Sleep会影响性能 然而 尽管我已经找到了几种更好的方法 但我还没有找到一种方法来包含它们而不弄乱代码 package platf
  • 将泛型与 Firebase snapshot.getValue() 结合使用的最佳实践

    TL DR 如何正确使用 Firebase DataSnapshot getValue 的泛型类 用例 我想使用 Firebase 为我的所有实体 其中一堆 实现一个通用远程数据源类 当监听数据更改时 我想从 datasnapshot 获取
  • 将两个表视图绑定在一起,以便它们同步滚动

    我想将两个表视图绑定在一起 以便它们同步滚动 我怎么做 我无法找到如何访问表格视图的滚动条 我做了一个CSS hack来将Tableview与外部滚动条绑定 一个滚动条控制两个表格视图 我的想法的概述 创建两个表视图 制作一个垂直滚动条 在
  • 将 uiautomator 测试用例与 Android 中的应用程序代码集成

    我正在使用 Eclipse IDE 这是我的 uiautomator 测试用例代码 public class caltest extends UiAutomatorTestCase public void testDemo throws U
  • 无法在 Vaadin Maven 项目上运行 mvn vaadin:compile

    当我运行命令 mvn vaadin compile 时出现此错误 INFO BUILD FAILURE INFO INFO Total time 1 039s INFO Finished at Thu Mar 20 11 35 00 CET
  • 根据条件更改 JSlider 的最小值和最大值

    我正在 Netbeans 中创建 Swing GUI 此 GUI 的目的是打开一个 缓冲 图像 在 JLabel 中作为图标 并对其应用仿射变换 现在我正在做 4 个转换 如下所示 现在 每个变换都需要两个滑块来更改 X 和 Y 值 但旋转
  • 在 Android 应用程序中读取 CSV 文件

    我正在开发一个概念验证应用程序 以便我可以在我正在制作的更大的应用程序中实现该功能 我对 Java 和 Android 开发有点陌生 但希望这个问题不会太简单或太复杂 基本上 我试图从 CSV 文件中读取字符串列表 并使其可用于在应用程序的
  • 为什么这个 SimpleDateFormat 无法解析这个日期字符串?

    简单日期格式 SimpleDateFormat pdf new SimpleDateFormat MM dd yyyy hh mm ss SSSaa 抛出的异常pdf parse Mar 30 2010 5 27 40 140PM java
  • Servlet上下文和Spring应用程序上下文的本质区别

    我正在阅读 spring 框架文档 现在我在应用范围概念 http docs spring io spring docs current spring framework reference htmlsingle beans factory
  • 对 JFace Treeviewer 多列进行排序

    我希望用户能够对TreeViewer只要他想 只要单击列标题即可 但是我不知道正确的方法 我发现我们可以使用ViewerComparator对不同的元素进行排序 但是 我不知道如何设置侦听器以便能够正确进行升序或降序排序 有没有办法让 JF
  • 使用当前日期时间的 RecyclerView 的动态节标题

    我将使用 RecyclerView 作为节标题 我想在 SQLite 数据库中插入每个日期和时间数据时创建节标题 我按照以下链接获取了此解决方案 但没有成功 请参考下图 对于上面的图像数据 使用以下代码或部分是静态的 List
  • 在文件中查找一行并将其删除

    我正在寻找一个小代码片段 它将在文件中找到一行并删除该行 不是内容而是行 但找不到 例如 我在以下文件中 我的文件 txt aaa bbb ccc ddd 需要有这样的功能 public void removeLine String lin
  • 无法在 JDBCPreparedStatement 中使用 LIKE 查询吗?

    查询代码及查询方式 ps conn prepareStatement select instance id from eam measurement where resource id in select RESOURCE ID from
  • 为什么浮点数有符号零?

    为什么双打有 0也 0 其背景和意义是什么 0 通常 被视为0 当一个negative浮点数非常接近零 可以考虑0 要明确的是 我指的是算术下溢 http en wikipedia org wiki Arithmetic underflow
  • Postgresql JDBC 驱动程序中的批量更新在自动提交中回滚

    我正在使用 postgres 9 3 1100 jdbc41 JDBC4 驱动程序进行批量插入 根据 JDBC 规范 其可达 到应用程序以禁用自动提交并提交或 回滚事务 就我而言 我没有使用任何事务 即自动提交为真 但如果批次中的其中一个插
  • 尝试从输入流检索文本时应用程序挂起

    情况 我确实查看了您的代码 正如我怀疑的那样 您的问题与您发布的代码完全无关 您的 GUI 完全忽略 Swing 线程规则 并在主 Swing 事件线程 称为Event Dispatch T螺纹或EDT 由于该线程负责所有 Swing 绘图

随机推荐

  • 如何在 IndexedDB 中进行 JOIN 类型查询

    我尝试按照以下教程进行操作http hacks mozilla org 2010 06 comparing indexeddb and webdatabase http hacks mozilla org 2010 06 comparing
  • 如何在 jquery 表单验证上显示独特的成功消息

    希望你能在这方面帮助我 我目前正在使用这个 jQuery 插件 验证 主页 http bassistance de jquery plugins jquery plugin validation 我一直在这里阅读相关问题 但这是最接近的 h
  • 我可以用什么来替换 HTML 中的   ?

    nbsp nbsp 我觉得很丑 边距和 或填充 CSS 属性 如下所示 p style padding left 10px Hello p 值得注意的是 放置这样的内联样式通常被认为是不好的做法 您通常在外部 css 文件中声明一个选择器并
  • 服务器场(服务计划)SKU

    是否有文档列出了 Azure 应用服务计划 服务器场 支持的 sku 名称和层 例如 名称 S1 等级 标准 S1 标准 和 名称 Y1 层 动态 功能消耗计划 支持的值列表 是否有第二年的消费计划 和服务器配置确实有助于规划 有多种方法可
  • Rails 4 中“确认”条件的干净方法

    我的 Rails4 页面上有一个使用 slim 语法的 link to 以下链接 to link to exports path data confirm Are you sure 现在需要仅在特定条件下显示确认消息 我们如何在rails4
  • 如何删除数据框中值的顺序不重要的行

    我有一个像这样的数据框 source target weight 1 2 5 2 1 5 1 2 5 1 2 7 3 1 6 1 1 6 1 3 6 我的目标是删除重复的行 但源列和目标列的顺序并不重要 事实上 两列的顺序并不重要 应该将其
  • 使用 Linq to SQL 删除表中的行

    我有一个体育数据库 其中有一个表 groupmembers 其中包含字段 ID groupID 和 memberID 我从名为 txtRemoveGroupMember 的文本框中获取memberID 并从复选框列表中获取groupID 现
  • 使用 Boost Spirit 解析语法

    我正在尝试解析像下面这样的树表达式之类的 C 函数 使用精神解析器框架 http en wikipedia org wiki Spirit Parser Framework F A B GREAT SOME NOT C YES 为此 我尝试
  • 如何在作为协议类型的 Swift 通用数据结构中使用弱引用?

    我想在通用数据结构中使用弱引用 在里面 下面是数组的示例 但通常是任何泛型类型 我几乎可以得到它 上班 我的实验开始得很顺利 以下作品 Array of weak references OK struct WeakReference
  • 更改 ListView 阴影颜色和大小

    当 ListView 中的项目列表比 ListView 的大小长时 您会看到一个阴影 指示上方或下方有更多项目 默认情况下 该阴影是黑色的 这是不可取的 如果我将 cacheColorHint 设置为以下内容 android cacheCo
  • 调用布尔值的成员函数 fetchAll()

    我有以下问题 这个错误一直伴随着我 致命错误 未捕获错误 在 C xampp htdocs certificado functions php 49 中的布尔值上调用成员函数 fetchAll 堆栈跟踪 0 C xampp htdocs c
  • 在抽象方法上实现“after”装饰器

    我正在尝试编写一个抽象基类A它将有一个抽象方法run用户 开发人员预计会超载 我想强制执行一些 之后 行为自动应用于派生类B 这样之后B run 运行完毕后 将调用另一个标准方法 在数据管道中 这可以例如提交或回滚事务 有办法实现这一点吗
  • 用周围值的平均值替换缺失值

    我的数据集如下所示 我们称之为 a date value 2013 01 01 12 2 2013 01 02 NA 2013 01 03 NA 2013 01 04 16 8 2013 01 05 10 1 2013 01 06 NA 2
  • THREE.js 使用 DOMElements 的 SphereGeometry 全景热点

    我使用以下命令创建了一个简单的 WebGL 3D 全景应用程序SphereGeometry PerspectiveCamera and a CanvasTexture 现在 我希望通过在场景的某些部分添加 热点 来使场景栩栩如生Sphere
  • 为什么我的 takeWhile 无法与我的 Stream 配合使用

    以下代码打印 1 令人困惑的是 如果我删除评论 它会返回 4 这正是我所期望的 var max 0 lazy val list Stream Int 1 Stream from 2 list takeWhile x gt max x x l
  • 非常快速的 3D 距离检查?

    有没有一种方法可以进行快速而肮脏的 3D 距离检查 虽然结果很粗糙 但速度非常快 我需要进行深度排序 我用STLsort像这样 bool sortfunc CBox a CBox b return a gt Get3dDistance Pl
  • iPhone 音量已更改事件(音量已达到最大)

    我在用着 AudioSessionAddPropertyListener kAudioSessionProperty CurrentHardwareOutputVolume audioVolumeChangeListenerCallback
  • 如何按哈希值之一对哈希引用数组进行排序?

    首先 请原谅我生锈的 Perl 我正在尝试修改 Bugzilla 的 whine pl 以生成按严重性排序的错误列表 所以它给了我一个哈希引用数组 每个哈希值都包含有关特定错误的大量信息 ID 受让人 严重性等 我想按严重性对数组进行排序
  • 旧的 Firebase Analytics 事件报告发生了什么?

    最近的 Firebase 控制台更新后 无法找到按内容类型列出的 select content 事件的报告 以及按 item id 找到的选定内容类型的报告 我使用这些报告来研究我的应用程序行为 方法是记录它们 Analytics logE
  • 仅通过一个 SocketChannel 发送多条消息

    读完本教程后 http rox xmlrpc sourceforge net niotut http rox xmlrpc sourceforge net niotut 这是关于编写非阻塞服务器和客户端 我阅读了NIO部分 跳过了SSL部分