Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java nettynio中承诺的异步更新_Java_Sockets_Web_Netty_Nio - Fatal编程技术网

Java nettynio中承诺的异步更新

Java nettynio中承诺的异步更新,java,sockets,web,netty,nio,Java,Sockets,Web,Netty,Nio,我有一个交换信息的服务器和客户端架构。我想从服务器返回连接通道的数量。我想使用promise将服务器的消息返回给客户端。我的代码是: public static void callBack () throws Exception{ String host = "localhost"; int port = 8080; try { Bootstrap b = new Bootstrap(); b.group(workerGroup);

我有一个交换信息的服务器和客户端架构。我想从服务器返回连接通道的数量。我想使用promise将服务器的消息返回给客户端。我的代码是:

public static void callBack () throws Exception{

   String host = "localhost";
   int port = 8080;

   try {
       Bootstrap b = new Bootstrap();
       b.group(workerGroup);
       b.channel(NioSocketChannel.class);
       b.option(ChannelOption.SO_KEEPALIVE, true);
       b.handler(new ChannelInitializer<SocketChannel>() {
        @Override
           public void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(), new ClientHandler(promise));
           }
       });
       ChannelFuture f = b.connect(host, port).sync();
       //f.channel().closeFuture().sync();
   }
   finally {
    //workerGroup.shutdownGracefully();
   }
}

public static void main(String[] args) throws Exception {

  callBack();
  while (true) {

    Object msg = promise.get();
    System.out.println("The number if the connected clients is not two");
    int ret = Integer.parseInt(msg.toString());
    if (ret == 2){
        break;
    }
  }
  System.out.println("The number if the connected clients is two");
}

客户机处理程序中存储从服务器接收到的消息的代码。

在Netty框架中,a和a是一次写入对象,这一原则使它们更易于在多线程环境中使用

由于承诺不能满足您的要求,我们需要看看其他技术是否适合您的条件,您的条件基本上可以归结为:

  • 从多个线程读取
  • 仅从单个线程写入(在Netty通道内,读取方法只能由1个线程同时执行,除非通道标记为可共享)
对于这些需求,最合适的匹配是volatile变量,因为这对于读取是线程安全的,并且可以安全地由1个线程更新,而不必担心写入顺序

要使用volatile变量更新代码,需要进行一些修改,因为我们无法轻松地将引用链接传递到函数中的变量,但必须传递更新后端变量的函数

private static volatile int connectedClients = 0;
public static void callBack () throws Exception{
    //....
           ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(),
                                 new ClientHandler(i -> {connectedClients = i;});
    //....
}

public static void main(String[] args) throws Exception {

  callBack();
  while (true) {
    System.out.println("The number if the connected clients is not two");
    int ret = connectedClients;
    if (ret == 2){
        break;
    }
  }
  System.out.println("The number if the connected clients is two");
}

public class ClientHandler extends ChannelInboundHandlerAdapter {
  public final IntConsumer update;
  public ClientHandler(IntConsumer update) {
      this.update = update;
  }

  @Override
  public void channelActive(ChannelHandlerContext ctx) throws Exception {
      RequestData msg = new RequestData();
      msg.setIntValue(123);
      msg.setStringValue("all work and no play makes jack a dull boy");
      ctx.writeAndFlush(msg);
  }

  @Override
  public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
      System.out.println(msg);
      update.accept(Integer.parseInt(msg));
  }
} 
虽然上面的方法应该可以工作,但我们很快就会看到主类中的While循环占用了大量的CPU时间,这可能会影响本地客户端系统的其他部分,幸运的是,如果我们向系统中添加其他部分,即同步,这个问题也是可以解决的。通过将
connectedClients
的初始读取放在同步块之外,我们仍然可以从“真”情况下的快速读取中获益,而“假”情况下,我们可以确保可以在系统其他部分使用的重要CPU周期的安全

为了解决这个问题,我们在阅读时使用以下步骤:

  • connectedClients
    的值存储在单独的变量中
  • 将此变量与目标值进行比较
  • 如果这是真的,那么就尽早打破循环
  • 如果为false,则进入同步块内部
  • 开始一个while-true循环
  • 再次读取变量,因为现在可能会更改该值
  • 检查状况,如果现在状况正确,则断开
  • 如果没有,请等待值的更改
  • 写作时应注意以下几点:

  • 同步化
  • 更新值
  • 唤醒等待此值的所有其他线程
  • 这可以通过以下代码实现:

    private static volatile int connectedClients = 0;
    private static final Object lock = new Object();
    public static void callBack () throws Exception{
        //....
               ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(),
                                     new ClientHandler(i -> {
                   synchronized (lock) {
                       connectedClients = i;
                       lock.notifyAll();
                   }
               });
        //....
    }
    
    public static void main(String[] args) throws Exception {
    
      callBack();
      int connected = connectedClients;
      if (connected != 2) {
          System.out.println("The number if the connected clients is not two before locking");
          synchronized (lock) {
              while (true) {
                  connected = connectedClients;
                  if (connected == 2)
                      break;
                  System.out.println("The number if the connected clients is not two");
                  lock.wait();
              }
          }
      }
      System.out.println("The number if the connected clients is two: " + connected );
    }
    
    服务器端更改 然而,并不是所有的问题都与客户端有关


    由于您向github存储库发布了一个链接,因此当有新用户加入时,您永远不会从服务器向旧客户端发送请求。因为没有这样做,所以客户端永远不会收到有关更改的通知,请确保也这样做。

    当您说promise时,您的意思是非阻塞吗?我的意思是这个对象msg=promise.get();,此值包含服务器的重新调谐消息。您可以根据您的问题按照我的答案回答不同的问题@konstantin,您的意思是:
    promise.get()
    返回客户端(通道)的数量已连接到您的服务器??在客户端处理程序中,我正在存储从客户端读取的消息。当我尝试将ConnectedClient添加到InitChannel时(新建ClientHandler(I->{connectedClients=I;})我接收到不兼容的类型,它在接收lambda参数时需要int。@konstantin您注意到我调整了
    ClientHandler
    ,我将参数从
    Promise
    更改为
    IntConsumer
    。如果您有一个类型为
    IntConsumer
    的参数,您可以使用接受1的lamba块int作为输入,这是我用于将结果传播到另一个类的方法。好的,我正确编写了代码。我运行了两个客户端,但在这两个客户端中我都收到了以下消息:2017年11月2日11:43:09 AM io.netty.channel.DefaultChannelPipeline onUnhandledInboundException警告:exceptionCaught()事件被触发,并到达管道的尾部。这通常意味着管道中的最后一个处理程序没有处理异常。java.lang.ClassCastException:chat.ResponseData无法转换为java.lang.Integer更新的代码可以在这里找到,这可能是我在
    CLientHandler内部的原始代码中遗漏的内容
    ,而不是
    update.accept(Integer.parseInt(msg));
    ,而是
    update.accept(((RequestData)msg.getIntValue());
    ,它直接从请求数据对象提取大小
    private static volatile int connectedClients = 0;
    private static final Object lock = new Object();
    public static void callBack () throws Exception{
        //....
               ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(),
                                     new ClientHandler(i -> {
                   synchronized (lock) {
                       connectedClients = i;
                       lock.notifyAll();
                   }
               });
        //....
    }
    
    public static void main(String[] args) throws Exception {
    
      callBack();
      int connected = connectedClients;
      if (connected != 2) {
          System.out.println("The number if the connected clients is not two before locking");
          synchronized (lock) {
              while (true) {
                  connected = connectedClients;
                  if (connected == 2)
                      break;
                  System.out.println("The number if the connected clients is not two");
                  lock.wait();
              }
          }
      }
      System.out.println("The number if the connected clients is two: " + connected );
    }