Netty 客户端到服务器消息 [英] Netty Client to Server message

查看:23
本文介绍了Netty 客户端到服务器消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这实际上是我在这里发表的第一篇文章,我一直在努力解决这个问题,但我终于打电话给了国旗,并试图就这个主题寻求一些帮助.

This is actually my first post on here and I have been trying to figure this out for some time but I am finally calling in the flag and going to try to get some help on this topic.

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

So I have a Client and a Server that was modeled after the echo client/server and the secure chat client/server. I am not interested in the SSL part of the chat and using the echo just to ensure that I am getting responses to and from the client/server. I will add all the pertinent code at the bottom of this post. The problem I am getting at the moment is that I can send a message from the server to the client upon the client connecting but I am not able to send a message from the client to the Server upon the server sending the client the initial message. The message being sent from the server is:

Welcome to the server!

来自客户端的消息是

test

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

I should know that I got the message from the client cause it should echo back

[You] test

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

I do know that the Server sees the Client and it gives me status updates but I cannot send a message to the server for some reason. Now for a question on top of this... By some chance I am currently using a StringDecoder and StringEncoder as the Decoder and Encoder... If you are making a game (which is what I am doing) and you will have things like logins, player movements, world updates, etc... is sending Strings the best way to do this? I know I see a lot with byte streams and in my programming class I went through we touched on manipulating byte streams but I am still not 100% comfortable with them yet. If byte streams are the better/best way to do this then can someone please explain in some detail how it works to manipulate a byte stream to be able to handle different items.

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

As stated before this is the start of everything in the client:

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();
}

ClientHandler:

ClientHandler:

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());
}
}

最后是 ClientPipeline:

And finally the ClientPipeline:

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();
}
}

ServerChannelHandler:

ServerChannelHandler:

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!

");
}

@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() + "

");
        } else {
            c.write("[You] " + e.getMessage() + "

");
        }
    }
}

/**
 * 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;
}
}

我再次感谢您在理解这一点上给予我的任何帮助.

Once again everyone I appreciate any help you can give me on understanding this.

推荐答案

您忘记将 附加到 "test".应该是:channel.write("test ").`

You forgot to append to "test". It should be: channel.write("test ").`

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

As you see from the pipeline, the decoding part is composed of two handlers. The first one splits and merges the received data into a single line of string and strips the line ending from it. The second one converts the single line of string into java.lang.String.

在编码方面,只有一个处理程序,它将java.lang.String 转换为ByteBuf,仅此而已.也许最好引入一个名为 LineEncoderLineDecoderLineCodec 的处理程序来完成通常预期的工作:https://github.com/netty/netty/issues/1811

On the encoding side, there's only one handler, which converts a java.lang.String into ByteBuf, and that's all it does. Perhaps it is better introduce a handler called LineEncoder, LineDecoder, and LineCodec that does the usually expected job: https://github.com/netty/netty/issues/1811

这篇关于Netty 客户端到服务器消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆