Netty客户端到服务器的消息

2023-11-22

这实际上是我在这里发表的第一篇文章,我已经尝试解决这个问题有一段时间了,但我终于调用了flag,并尝试在这个主题上获得一些帮助。

所以我有一个客户端和一个服务器,它们是根据回显客户端/服务器和安全聊天客户端/服务器建模的。我对聊天的 SSL 部分不感兴趣,并且使用 echo 只是为了确保我收到客户端/服务器的响应。我将在这篇文章的底部添加所有相关代码。我目前遇到的问题是,我可以在客户端连接时从服务器向客户端发送消息,但在服务器向客户端发送初始消息时,我无法从客户端向服务器发送消息。从服务器发送的消息是:

Welcome to the server!

来自客户端的消息是

test

我应该知道我从客户端收到了消息,因为它应该回显

[You] test

我确实知道服务器看到客户端并为我提供状态更新,但由于某种原因我无法向服务器发送消息。现在,除此之外还有一个问题...我目前正在使用 StringDecoderStringEncoder 作为解码器和编码器...如果您正在制作游戏(这就是我正在做的事情)并且您将拥有诸如登录、玩家移动、世界更新等内容......发送字符串是执行此操作的最佳方式吗?我知道我看到了很多关于字节流的内容,在我的编程课上,我们接触到了字节流的操作,但我仍然对它们还不是 100% 满意。如果字节流是更好/最好的方法来做到这一点,那么有人可以详细解释它如何操作字节流以能够处理不同的项目。

如前所述,这是客户端中一切的开始:

public class Client {

public Client() {
    // Initialize the window
    GameWindow.init();
    // Initialize the server connection
    ClientHandler.init();
}

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

    // Set a default server address if one isn't specified in the arguments
    if (args.length < 2 || args.length > 3) {
        System.err.println("Usage: " + Client.class.getSimpleName() + " <host> <port> [<first message size>]");
        System.err.println("Using default values.");
    } else {
        // Parse arguments
        Settings.host = args[0];
        Settings.port = Integer.parseInt(args[1]);
    }

    // start client
    new Client();
}

客户端处理程序:

package simple.client.net;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.WriteCompletionEvent;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;

import simple.client.Settings;

public class ClientHandler extends SimpleChannelUpstreamHandler {

private static final Logger logger = Logger.getLogger(ClientHandler.class.getName());

public static Channel channel;

public ClientHandler() {
}

public static void init() {
    // Configure the client.
    ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));

    // Set up the pipeline factory.
    bootstrap.setPipelineFactory(new ClientPipelineFactory());

    // Start the connection attempt.
    ChannelFuture future = bootstrap.connect(new InetSocketAddress(Settings.host, Settings.port));

    // Wait until the connection is closed or the connection attempt fails.
    channel = future.awaitUninterruptibly().getChannel();

    // This is where the test write is <<------
    ChannelFuture test = channel.write("test");

    if (!future.isSuccess()) {
        future.getCause().printStackTrace();
        bootstrap.releaseExternalResources();
        return;
    }
}

@Override
public void channelBound(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Bound: " + e.getChannel().isBound());
}

@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Connected: " + e.getChannel().isConnected());
    System.out.println("Connected: " + e.getChannel().getRemoteAddress());
}

@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Closed: " + e.getChannel());
}

@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Disconnected: " + e.getChannel());
}

@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Open: " + e.getChannel().isOpen());
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
    System.out.println("Error: " + e.getCause());
}

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
    System.out.println("Message: " + e.getMessage());
}
}

最后是客户端管道:

package simple.client.net;

import static org.jboss.netty.channel.Channels.*;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

public class ClientPipelineFactory implements ChannelPipelineFactory {

public ChannelPipeline getPipeline() throws Exception {
    ChannelPipeline pipeline = pipeline();

    pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
    pipeline.addLast("decoder", new StringDecoder());
    pipeline.addLast("encoder", new StringEncoder());
    pipeline.addLast("handler", new ClientHandler());

    return pipeline;
}

}

服务器端:

package simple.server;

public class Server {
public static void main(String[] args) throws Exception {
    ServerChannelHandler.init();
}
}

服务器通道处理程序:

package simple.server;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import java.util.logging.Logger;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

public class ServerChannelHandler extends SimpleChannelHandler {

private static final Logger logger = Logger.getLogger(ServerChannelHandler.class.getName());

private static ChannelGroup channels;
private static ServerBootstrap bootstrap;

public ServerChannelHandler() {
}

/**
 * Initialize the Server Channel Handler
 */
public static void init() {
    // create a channels group to add incoming channels to
    channels = new DefaultChannelGroup();

    // create the server bootstrap (fancy word for pre-made server setup)
    bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(
            Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));

    // set the server pipeline factory
    bootstrap.setPipelineFactory(new ServerPipelineFactory());

    // server settings
    bootstrap.setOption("keepAlive", true);

    // bind the server to the port
    bootstrap.bind(new InetSocketAddress(Settings.PORT_ID));
}

@Override
public void channelBound(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Bound: " + e.getChannel());
}

@Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Connected: " + e.getChannel());
    channels.add(e.getChannel());
    e.getChannel().write("Welcome to the test server!\n\r");
}

@Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Closed: " + e.getChannel());
}

@Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Disconnected: " + e.getChannel());
}

@Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) {
    System.out.println("Open: " + e.getChannel());
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
    System.out.println("Error: " + e.getCause());
}

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
    System.out.println("Message: " + e.getMessage());
    for (Channel c : channels) {
        if (e.getMessage().equals("shutdown")) {
            shutdown();
        }
        if (c != e.getChannel()) {
            c.write("[" + e.getChannel().getRemoteAddress() + "] " + e.getMessage() + "\n\r");
        } else {
            c.write("[You] " + e.getMessage() + "\n\r");
        }
    }
}

/**
 * Shuts down the server safely
 */
public static final void shutdown() {
    channels.close();
    bootstrap.releaseExternalResources();
    System.exit(0);
}
}

服务器管道工厂:

package simple.server;

import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.handler.codec.frame.DelimiterBasedFrameDecoder;
import org.jboss.netty.handler.codec.frame.Delimiters;
import org.jboss.netty.handler.codec.string.StringDecoder;
import org.jboss.netty.handler.codec.string.StringEncoder;

import simple.server.decoder.Decoder;
import simple.server.encoder.Encoder;

public class ServerPipelineFactory implements ChannelPipelineFactory {
@Override
public ChannelPipeline getPipeline() throws Exception {
    ChannelPipeline pipeline = Channels.pipeline();

    pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
    pipeline.addLast("decoder", new StringDecoder());
    pipeline.addLast("encoder", new StringEncoder());
    pipeline.addLast("handler", new ServerChannelHandler());

    return pipeline;
}
}

我再次感谢大家为我理解这一点提供的任何帮助。


你忘了附加\r\n to "test"。它应该是:channel.write("test\r\n").`

从管道中可以看到,解码部分由两个处理程序组成。第一个将接收到的数据拆分并合并为一行字符串,并删除以它结尾的行。第二个将单行字符串转换为java.lang.String.

在编码方面,只有一个处理程序,用于将java.lang.String into ByteBuf,这就是它的全部作用。也许最好引入一个名为的处理程序LineEncoder, LineDecoder, and LineCodec完成通常预期的工作:https://github.com/netty/netty/issues/1811

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

Netty客户端到服务器的消息 的相关文章

随机推荐

  • ShareKit 发生变化?

    我没有太多使用 ShareKit 但我只想拥有三个共享选项 Facebook Twitter 和电子邮件 ShareKit 提供了更多选项 包括 更多 按钮 但是 我不需要 更多 选项 只需要三个选项 In SHKActionSheet m
  • 删除带有嵌套因素的条形图中每个面板未使用的因素

    前段时间我问了一个问题如何删除条形图中未使用的因素 感谢 Aaron 我为这个问题找到了一个有用的解决方案 现在 我面临着一个非常相似的问题 但我过去使用的解决方案不适用于这种情况 这是重现我正在使用的数据框的代码 set seed 17
  • 如何编写接受管道输入的 PowerShell 脚本?

    我正在尝试编写一个可以获取管道输入的PowerShell脚本 并且预计会这样做 但尝试类似 ForEach Object do something 从命令行使用脚本时实际上不起作用 如下所示 1 20 test ps1 有办法吗 注意 我了
  • 替换2个字符串之间的所有文本python

    可以说我有 a r Example This is a very annoying string that takes up multiple lines and h s a kind s of stupid symbols in it o
  • django 的模型 get_or_create 方法不应该包装在事务中吗?

    我正在浏览 django 的源代码并查看获取或创建 难道不应该用交易来包装吗 Thanks 看着这个差异看起来像修订8315 已在get or create 方法 Update 正如 reshefm 指出的 这个问题已在rev 8670 w
  • wordpress URL 以数字结尾

    我不确定这是否是一个已知问题或应该像这样的表现 任何 WordPress 网站 如果您在 URL 末尾添加数字 例如 http perishablepress com wordpress multisite mamp 我们在末尾添加 1 或
  • 如何在 python 中使用reportlab、rtl 和 bidi 创建包含波斯语(波斯语)文本的 PDF

    我一直在尝试使用英语 波斯语 数字或它们的组合的内容创建 PDF 文件 波斯语文本存在一些问题 例如 1 文字必须从右向左书写 2 单词中不同位置的字符之间存在差异 意味着字符根据周围的字符改变形状 3 因为句子是从右向左阅读的 所以普通的
  • 如何使用 ggplot 绘制 T-SNE 聚类图

    以下是使用 IRIS 数据的 t SNE 代码 library Rtsne iris unique lt unique iris Remove duplicates iris matrix lt as matrix iris unique
  • 为单个 Jenkins 作业构建多个 Maven 配置文件

    我正在尝试在单个 Jenkins 作业中构建多个 Maven 配置文件 每个配置文件都会更改一些代码 然后通过执行创建一个 jarmvn Pdev install then mvn Pprod install在命令行中 根据 Maven 使
  • 不能写成 for 循环的 while 循环示例

    我知道 while 循环可以做 for 循环可以做的任何事情 但是 for 循环可以做 while 循环可以做的事情吗 请举个例子 是的 很容易 while cond S for cond S
  • 将新字段更新到现有文档

    是否可以将新字段更新到现有文档 例如 有一个包含多个字段的文档 例如 ID 99999 Field1 text Field2 text 该文档已经在索引中 现在我想在该文档中插入一个新字段 而不使用旧数据 ID 99999 Field3 t
  • 查找流星集合中的最新条目

    我的任务听起来很简单 但我无法确定如何编写这个 我只想找到插入集合中的最新项目并将其显示在我的流星应用程序上 我一直在使用 Collection find 但没有任何实际结果 这是我尝试过的最后一行 请记住这些名称是占位符 我的集合在我的代
  • 我如何在 make 目标之间传递 ENV 变量

    我在 makefile 中有这样的 target1 export var1 test MAKE target2 target2 echo var1 这是空的 我有其他依赖项 所以我想在第一个目标中设置变量 然后所有子依赖项应该能够访问该变量
  • 如何避免动态调度?

    我有以下特点 struct ArtistInfo some fields pub trait Fetcher fn fetch self artist String gt ArtistInfo 我想要有几个不同的获取器 可以在不同的情况下使
  • 从 ggplot 中删除 n 个图例

    我试图从下面的图中删除 n 图例 我猜这与stat部分geom bar 但我不完全确定它显示的内容 因此不知道如何删除它 我确实想要填充图例show legends FALSE不是正确的选择 抱歉 如果这是重复的 但之后 我找了很多找不到答
  • 为什么我收到“无法加载扩展。‘content_security_policy’值无效”?

    我正在尝试创建一个 chrome 扩展 我的清单文件是 name Alert Beep action manifest version 3 version 0 1 description Beeps if alert is called c
  • 带有 Fragments 和 FragmentActivity 的 TabHost

    我正在开发一个 Android 应用程序 我想使用 3 个选项卡进行导航 每个选项卡使用片段 但我不知道如何创建执行此操作的结构 我想单独添加每个片段 因为每个片段都不同 但我不知道在 FragmentActivity 中的哪里添加它们 我
  • 在 Android Studio (cmake) 中使用预构建的共享库

    我想在我的 Android 应用程序中使用 C 共享库 我试图遵循hello libs来自 Google NDK 样本的示例 但不知何故它不起作用 看来我的库没有打包到 APK 中 我发现的所有教程都在使用 mk 文件 但我想使用cmake
  • 我应该如何保护 iOS 中的 SQLite 数据库?

    我正在开发一个医疗保健 iOS 应用程序 我希望对用户的数据进行加密 这样如果他们的 iPhone 被盗 窃贼将无法访问他们的健康信息 合法所有者应该能够访问他们的信息 与这个问题 我正在考虑使用SQL密码加密整个数据库 并将SQLCiph
  • Netty客户端到服务器的消息

    这实际上是我在这里发表的第一篇文章 我已经尝试解决这个问题有一段时间了 但我终于调用了flag 并尝试在这个主题上获得一些帮助 所以我有一个客户端和一个服务器 它们是根据回显客户端 服务器和安全聊天客户端 服务器建模的 我对聊天的 SSL