Netty入门之客户端与服务端通信(二)

Netty入门之客户端与服务端通信(二)

一.简介

  在上一篇博文中笔者写了关于Netty入门级的Hello World程序。书接上回,本博文是关于客户端与服务端的通信,感觉也没什么好说的了,直接上代码吧。

二.客户端与服务端的通信

2.1 服务端启动程序

public class MyServer {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            serverBootstrap.group(bossGroup, workerGroup)
                           .channel(NioServerSocketChannel.class)
                           .childHandler(new MyInitializer());

            ChannelFuture channelFuture = serverBootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();
        }finally{
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

2.2 服务端通道初始化程序

public class MyInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline =  ch.pipeline();
        /**
         * LengthFieldBasedFrameDecoder: 基于长度属性的帧解码器。
         * 客户端传递过来的数据格式为:
         *  BEFORE DECODE (14 bytes)         AFTER DECODE (14 bytes)
         *    +--------+----------------+      +--------+----------------+
         *    | Length | Actual Content |----->| Length | Actual Content |
         *    | 0x000C | "HELLO, WORLD" |      | 0x000C | "HELLO, WORLD" |
         *    +--------+----------------+      +--------+----------------+
         * 5个参数依次为:1.(maxFrameLength)每帧数据的最大长度.
         *              2.(lengthFieldOffset)length属性在帧中的偏移量。
         *           3.(lengthFieldLength)length属性的长度,需要与客户端 LengthFieldPrepender设置的长度一致,
         *               值的取值只能为1, 2, 3, 4, 8
         *           4.(lengthAdjustment)长度调节值, 当信息长度包含长度时候,用于修正信息的长度。
         *           5.(initialBytesToStrip)在获取真实的内容的时候,需要忽略的长度(通常就是length的长度)。
         *
         * 参考: http://blog.csdn.net/educast/article/details/47706599
         */
        pipeline.addLast("lengthFieldBasedFrameDecoder",
                            new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
        /**
         * LengthFieldPrepender: length属性在帧中的长度。只能为1,2,3,4,8。
         * 该值与对应的客户端(或者服务端)在解码时候使用LengthFieldBasedFrameDecoder中所指定的lengthFieldLength
         * 的值要保持一致。
         */
        pipeline.addLast("lengthFieldPrepender", new LengthFieldPrepender(3));
        //StringDecoder字符串的解码器, 主要用于处理编码格式
        pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
        //StringDecoder字符串的编码器,主要用于指定字符串的编码格式
        pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));

        pipeline.addLast(new MyHandler()); //自定义的Handler
    }
}

2.3 自定义Handler

public class MyHandler extends SimpleChannelInboundHandler<String>{

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(ctx.channel().remoteAddress() + ":" + msg);
        ctx.channel().writeAndFlush("from server: 草泥马");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "********");
        System.out.println("server handler added**********");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "********");
        System.out.println("server channel register****");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "********");
        System.out.println("server channel actieve****");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

2.4客户端启动程序

public class MyClient {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        try{
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class).handler(new ClientInitializer());

            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8899).sync();
            channelFuture.channel().closeFuture().sync();
        }finally{
            eventLoopGroup.shutdownGracefully();
        }
    }
}

2.5客户端通道初始化

public class ClientInitializer extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline =  ch.pipeline();
        pipeline.addLast("lengthFieldBasedFrameDecoder",
                            new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
        pipeline.addLast("lengthFieldPrepender", new LengthFieldPrepender(3));
        pipeline.addLast("stringDecoder", new StringDecoder(CharsetUtil.UTF_8));
        pipeline.addLast("stringEncoder", new StringEncoder(CharsetUtil.UTF_8));

        pipeline.addLast(new MyClientHandler());
    }
}

2.5客户端自定义Handler

public class MyClientHandler extends SimpleChannelInboundHandler<String>{

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(ctx.channel().remoteAddress());
        System.out.println(msg);
        ctx.channel().writeAndFlush("to Server: 草泥马");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "...........");
        ctx.channel().writeAndFlush("来自于客户端的问候!");
        System.out.println("client channel Active...");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "...........");
        System.out.println("client hanlder added...");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println(System.currentTimeMillis() + "...........");
        System.out.println("client channel register...");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client channel inactive...");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client channel unregister...");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

三. 运行测试

运行服务端启动代码,然后在运行客户端启动代码,就可以看见千万只"草泥马"在崩腾。

时间: 2024-12-06 12:20:32

Netty入门之客户端与服务端通信(二)的相关文章

警察与小偷的实现之一客户端与服务端通信

来源于ISCC 2012 破解关第四题 目的是通过逆向police,实现一个thief,能够与police进行通信 实际上就是一个RSA加密通信的例子,我们通过自己编写客户端和服务端来实现上面的thief和police的功能.. 要通信,这们这次先通过python写出可以进行网络连接的客户端与服务端.. 服务端代码 #!/usr/bin/env python import SocketServer from time import ctime HOST = '127.0.0.1' PORT =

Android客户端与PHP服务端通信(二)

概述 本节通过一个简单的demo程序简单的介绍Android客户端通过JSON向PHP服务端提交订单,PHP服务端处理订单后,通过JSON返回结果给Android客户端.正常来讲,PHP服务端在处理订单过程中,需要与MySQL数据库交互,这里为了简单起见,暂时省掉MySQL. 通信格式 首先,需要定下客户端与服务端之间通信格式,如下表 Android客户端 客户端与服务端采用JSON数据格式通信,同时采用HTTP通信协议交互,采用POST方式提交结果.同时还要注意一点,与WEB服务器通信的过程需

Python socket编程客户端与服务端通信

目标:实现客户端与服务端的socket通信,消息传输. 客户端 客户端代码: from socket import socket,AF_INET,SOCK_STREAM #服务端的ip地址 server_ip = '127.0.0.1' #服务端socket绑定的端口号 server_port = 20000 if __name__ == '__main__': while True: str_msg = input("请输入要发送信息:") if str_msg != "&

使用多线程实现多个客户端与服务端通信1

Server.java package socket; import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket; /** * 聊天室服务端 * @author 小

二、网络编程-socket之TCP协议开发客户端和服务端通信

知识点:之前讲的udp协议传输数据是不安全的,不可靠不稳定的,tcp协议传输数据安全可靠,因为它们的通讯机制是不一样的.udp是用户数据报传输,也就是直接丢一个数据包给另外一个程序,就好比寄信给别人,信丢了你也不知道,tcp传输需要先和服务端建立连接,当客户端与服务器连接时,服务器会给出应答,我俩连上了,而且数据传过来还会进行一个数据包数量验证,不一致会重新发送,还有其他种种验证,总之保证了数据传输安全可靠   这一章主要介绍使用套接字,编写一个tcp协议客户端和服务端.同样要用到上一章节提到小

Netty实现客户端和服务端通信简单例子

Netty是建立在NIO基础之上,Netty在NIO之上又提供了更高层次的抽象. 在Netty里面,Accept连接可以使用单独的线程池去处理,读写操作又是另外的线程池来处理. Accept连接和读写操作也可以使用同一个线程池来进行处理.而请求处理逻辑既可以使用单独的线程池进行处理,也可以跟放在读写线程一块处理.线程池中的每一个线程都是NIO线程.用户可以根据实际情况进行组装,构造出满足系统需求的并发模型. Netty提供了内置的常用编解码器,包括行编解码器[一行一个请求],前缀长度编解码器[前

WCF客户端与服务端通信简单入门教程

服务端 1.新建空白解决方案,然后再空白解决方案中新建:WCF服务应用程序.建完后如图: 2.删掉自动生成的IService1.cs和Service.svc并添加WCF服务文件StudentService.svc,VS会自动生成IStudentService.cs 在添加一个Student类,如图: Student.cs: /// <summary> /// DataContract数据约定,保证student类在WCF调用中被序列化 /// DataMember 在被序列化的成员变量中必须加

使用socket实现简单的客户端和服务端通信(C#语言)

1.主要思路: (1) 服务端开启监听线程,等待客户端的连接. 每个socket连接放到独立线程中处理. (2) 服务端和客户端使用约定的消息格式通信.对于比较复杂的消息(如向服务端传递一个实例),可以使用json封装传输. (3) 每个连接的客户端,注册唯一的ClientID,在服务端以此来区分消息的来源. 2.代码构成 实现该样例包含两个cs的客户端程序. 分别为 服务端 和 客户端. 3.主要代码: (1) 服务端 xaml <Window x:Class="WpfApplicati

ssl客户端与服务端通信的demo

服务端程序流程 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <errno.h> 4 #include <string.h> 5 #include <sys/types.h> 6 #include <netinet/in.h> 7 #include <sys/socket.h> 8 #include <sys/wait.h> 9 #include &