1. 程式人生 > >Socket通訊-Netty框架實現Java通訊(字串資訊的傳輸)

Socket通訊-Netty框架實現Java通訊(字串資訊的傳輸)

Netty簡介

Netty是由JBOSS提供的一個java開源框架。Netty提供非同步的、事件驅動的網路應用程式框架和工具,用以快速開發高效能、高可靠性的網路伺服器和客戶端程式。

也就是說,Netty 是一個基於NIO的客戶、伺服器端程式設計框架,使用Netty 可以確保你快速和簡單的開發出一個網路應用,例如實現了某種協議的客戶,服務端應用。Netty相當簡化和流線化了網路應用的程式設計開發過程,例如,TCP和UDP的socket服務開發。

“快速”和“簡單”並不用產生維護性或效能上的問題。Netty 是一個吸收了多種協議的實現經驗,這些協議包括FTP,SMTP,HTTP,各種二進位制,文字協議,並經過相當精心設計的專案,最終,Netty 成功的找到了一種方式,在保證易於開發的同時還保證了其應用的效能,穩定性和伸縮性。

本文的目的

使用Netty實現一個Socket通訊,包括客戶端和服務端,通過服務端進行監聽,客戶端傳送資訊,服務端可進行接收,並進行返回資料,完成一個完整的通訊。

工程結構

這裡寫圖片描述

POM檔案配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.taowd.socket</groupId> <artifactId>SocketDemo2</artifactId> <version>0.0.1-SNAPSHOT</version> <dependencies> <!-- https://mvnrepository.com/artifact/io.netty/netty-all --> <dependency
>
<groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.6.Final</version> </dependency> </dependencies> </project>

服務端程式碼

EchoServer.java

package Server;

import java.nio.charset.Charset;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;

public class EchoServer {
    private final int port;

    public EchoServer(int port) {
        this.port = port;
    }

    public void start() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup();

        EventLoopGroup group = new NioEventLoopGroup();
        try {
            ServerBootstrap sb = new ServerBootstrap();
            sb.option(ChannelOption.SO_BACKLOG, 1024);
            sb.group(group, bossGroup) // 繫結執行緒池
                    .channel(NioServerSocketChannel.class) // 指定使用的channel
                    .localAddress(this.port)// 繫結監聽埠
                    .childHandler(new ChannelInitializer<SocketChannel>() { // 繫結客戶端連線時候觸發操作

                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("報告");
                            System.out.println("資訊:有一客戶端連結到本服務端");
                            System.out.println("IP:" + ch.localAddress().getHostName());
                            System.out.println("Port:" + ch.localAddress().getPort());
                            System.out.println("報告完畢");

                            ch.pipeline().addLast(new StringEncoder(Charset.forName("GBK")));
                            ch.pipeline().addLast(new EchoServerHandler()); // 客戶端觸發操作
                            ch.pipeline().addLast(new ByteArrayEncoder());
                        }
                    });
            ChannelFuture cf = sb.bind().sync(); // 伺服器非同步建立繫結
            System.out.println(EchoServer.class + " 啟動正在監聽: " + cf.channel().localAddress());
            cf.channel().closeFuture().sync(); // 關閉伺服器通道
        } finally {
            group.shutdownGracefully().sync(); // 釋放執行緒池資源
            bossGroup.shutdownGracefully().sync();
        }
    }

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

        new EchoServer(8888).start(); // 啟動
    }
}

EchoServerHandler.java

package Server;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    /*
     * channelAction
     *
     * channel 通道 action 活躍的
     *
     * 當客戶端主動連結服務端的連結後,這個通道就是活躍的了。也就是客戶端與服務端建立了通訊通道並且可以傳輸資料
     *
     */
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().localAddress().toString() + " 通道已啟用!");
    }

    /*
     * channelInactive
     *
     * channel 通道 Inactive 不活躍的
     *
     * 當客戶端主動斷開服務端的連結後,這個通道就是不活躍的。也就是說客戶端與服務端的關閉了通訊通道並且不可以傳輸資料
     *
     */
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().localAddress().toString() + " 通道不活躍!");
        // 關閉流

    }

    /**
     * 
     * @author Taowd
     * TODO  此處用來處理收到的資料中含有中文的時  出現亂碼的問題
     * 2017年8月31日 下午7:57:28
     * @param buf
     * @return
     */
    private String getMessage(ByteBuf buf) {
        byte[] con = new byte[buf.readableBytes()];
        buf.readBytes(con);
        try {
            return new String(con, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 功能:讀取伺服器傳送過來的資訊
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 第一種:接收字串時的處理
        ByteBuf buf = (ByteBuf) msg;
        String rev = getMessage(buf);
        System.out.println("客戶端收到伺服器資料:" + rev);

    }

    /**
     * 功能:讀取完畢客戶端傳送過來的資料之後的操作
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        System.out.println("服務端接收資料完畢..");
        // 第一種方法:寫一個空的buf,並重新整理寫出區域。完成後關閉sock channel連線。
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
        // ctx.flush();
        // ctx.flush(); //
        // 第二種方法:在client端關閉channel連線,這樣的話,會觸發兩次channelReadComplete方法。
        // ctx.flush().close().sync(); // 第三種:改成這種寫法也可以,但是這中寫法,沒有第一種方法的好。
    }

    /**
     * 功能:服務端發生異常的操作
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        System.out.println("異常資訊:\r\n" + cause.getMessage());
    }
}

客戶端程式碼

EchoClient.java

package Cilent;

import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.bytes.ByteArrayEncoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;

public class EchoClient {
    private final String host;
    private final int port;

    public EchoClient() {
        this(0);
    }

    public EchoClient(int port) {
        this("localhost", port);
    }

    public EchoClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void start() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group) // 註冊執行緒池
                    .channel(NioSocketChannel.class) // 使用NioSocketChannel來作為連線用的channel類
                    .remoteAddress(new InetSocketAddress(this.host, this.port)) // 繫結連線埠和host資訊
                    .handler(new ChannelInitializer<SocketChannel>() { // 繫結連線初始化器
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            System.out.println("正在連線中...");
                            ch.pipeline().addLast(new StringEncoder(Charset.forName("GBK")));
                            ch.pipeline().addLast(new EchoClientHandler());
                            ch.pipeline().addLast(new ByteArrayEncoder());
                            ch.pipeline().addLast(new ChunkedWriteHandler());

                        }
                    });
            // System.out.println("服務端連線成功..");

            ChannelFuture cf = b.connect().sync(); // 非同步連線伺服器
            System.out.println("服務端連線成功..."); // 連線完成

            cf.channel().closeFuture().sync(); // 非同步等待關閉連線channel
            System.out.println("連線已關閉.."); // 關閉完成

        } finally {
            group.shutdownGracefully().sync(); // 釋放執行緒池資源
        }
    }

    public static void main(String[] args) throws Exception {
        new EchoClient("127.0.0.1", 8888).start(); // 連線127.0.0.1/65535,並啟動

    }
}

EchoClientHandler.java

package Cilent;

import java.nio.charset.Charset;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    /**
     * 向服務端傳送資料
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客戶端與服務端通道-開啟:" + ctx.channel().localAddress() + "channelActive");

        String sendInfo = "Hello 這裡是客戶端  你好啊!";
        System.out.println("客戶端準備傳送的資料包:" + sendInfo);
        ctx.writeAndFlush(Unpooled.copiedBuffer(sendInfo, CharsetUtil.UTF_8)); // 必須有flush

    }

    /**
     * channelInactive
     *
     * channel 通道 Inactive 不活躍的
     *
     * 當客戶端主動斷開服務端的連結後,這個通道就是不活躍的。也就是說客戶端與服務端的關閉了通訊通道並且不可以傳輸資料
     *
     */
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("客戶端與服務端通道-關閉:" + ctx.channel().localAddress() + "channelInactive");
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        System.out.println("讀取客戶端通道資訊..");
        ByteBuf buf = msg.readBytes(msg.readableBytes());
        System.out.println(
                "客戶端接收到的服務端資訊:" + ByteBufUtil.hexDump(buf) + "; 資料包為:" + buf.toString(Charset.forName("utf-8")));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
        System.out.println("異常退出:" + cause.getMessage());
    }
}

執行結果圖

客戶端資訊
服務端資訊

相關推薦

Socket通訊-Netty框架實現Java通訊(字串資訊傳輸)

Netty簡介 Netty是由JBOSS提供的一個java開源框架。Netty提供非同步的、事件驅動的網路應用程式框架和工具,用以快速開發高效能、高可靠性的網路伺服器和客戶端程式。 也就是說,Netty 是一個基於NIO的客戶、伺服器端程式設計框架,使用Ne

AndroidAsync框架實現區域網通訊

package com.actiview.asynclib; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.

基於netty框架實現的TCP服務端程式

工程目錄結構 程式碼:NioServer main類 import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; import io.netty.channel.Channel

分布式架構的基石,簡單的 RPC 框架實現(JAVA)

測試 請求 消費 進制 runt trace 發布 @override etc   RPC架構   RPC 的全稱是 Remote Procedure Call,它是一種進程間通信方式。允許像調用本地服務一樣調用遠程服務。   1.RPC 框架原理   RPC

Linux 程序間通訊——訊息佇列實現雙向通訊

函式: key_t ftok(const char *filename, int proj_id); 通過檔名和專案號獲得System V IPC鍵值(用於建立訊息佇列、共享記憶體所用) proj_id:專案號,不為0即可 返回:成功則返回鍵值,失敗則返回-1 函式: in

web Socketnetty框架支援高併發

ONE、分析HTTP與WEB SOCKET的優缺點: 一、HTTP協議的弊端 將HTTP協議的主要弊端總結如下: (1)半雙工協議:可以在客戶端和服務端2個方向上傳輸,但是不能同時傳輸。同一時刻,只能在一個方向上傳輸。 (2) HTTP訊息冗長

使用Python的Flask框架實現視訊的流媒體傳輸

Flask 是一個 Python 實現的 Web 開發微框架。這篇文章是一個講述如何用它實現傳送視訊資料流的詳細教程。我敢肯定,現在你已經知道我在O'Reilly Media上釋出了有關Flask的一本書和一些視訊資料。在這些上面,Flask框架介紹的覆蓋面是相當完整的,出於某種原因,也有一小部分的功能沒有太

【HttpClient學習與實戰】1.使用httpClient實現get與post資訊傳輸

一般網路會給我們提供許多資料介面,我們的一些資訊並不是我們本系統提供而是第三方給我們提供的,他們通常會給我們一個提供資料來源的介面,訪問這個介面可以獲取相應的資料用於我們自己的應用中(WebService和現如今的json/xml通過http資訊的傳輸模式都是如此)。 ht

Netty框架的簡單使用,實現socket通訊

個人部落格:haichenyi.com。感謝關注   題外話,很多人都把JDK1.4提供的NIO稱之為非同步非阻塞I/O;其實,並不然,從嚴格意義上面講,它只能稱為非阻塞I/O。在JDK1.7提供的NIO 2.0,新增了非同步的套接字通道Channel,它才是

Java學習筆記之--------網路程式設計之Socket通訊----聊天室實現

Socket通訊 網路上的兩個程式通過一個雙向的通訊連線實現資料的交換,這個連線的一端稱為一個socket。基於TCP/IP協議,建立穩定的點對點的通訊。 特點:實時、快速、安全性高、佔用系統資源多、效率低。 通常也稱作"套接字",套接字是一種程序間的資料交換機制。這些程序既可以在同一機

Java 實現socket 與伺服器實現實時通訊

        現在有一個需求,就是要去給一臺客戶端主動去傳送指令,或者推送訊息,就尋求朋友問了問告訴我說socket可以實現,所以就在網上找了些資料一遍學習,一遍測試,現在把我最後的成果記錄下來。        如果對於socket有概念上的不理解的話,可以去百度一下會有很

JAVA通訊(2)--實現簡單的RPC框架

一、RPC簡介 RPC,全稱為Remote Procedure Call,即遠端過程呼叫,它是一個計算機通訊協議。它允許像呼叫本地服務一樣呼叫遠端服務。它可以有不同的實現方式。如RMI(遠端方法呼叫)、Hessian、Http invoker等。另外,RPC是

JAVA通訊(1)-- 使用Socket實現檔案上傳與下載

客戶端 /** * 檔案上傳客戶端 * * @author chen.lin * */ public class UploadClient extends JFrame { /** * */ priva

java socketnetty通訊

一、Socket簡單通訊1、先啟動server端import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /**

java SSM框架 websocket即時通訊 代碼生成器 shiro redis 後臺框架源碼

pdh 音頻 orf 元素 數據庫連接池 extra 數據庫連接 宋體 jpg 1. 權限管理:點開二級菜單進入三級菜單顯示 角色(基礎權限)和按鈕權限 角色(基礎權限): 分角色組和角色,獨立分配菜單權限和增刪改查權限。 按鈕權限: 給角色分配按鈕

Socket.IO介紹:支持WebSocket、用於WEB端的即時通訊框架

網絡 進行 最新版本 ajax 並且 移動 接口 事件 ODB 一、基本介紹   WebSocket是HTML5的一種新通信協議,它實現了瀏覽器與服務器之間的雙向通訊。而Socket.IO是一個完全由JavaScript實現、基於Node.js、支持WebSocket的協議

java 實現udp通訊

ket 地址 upd void ESS util dst 服務端 unknown 需求:應用A(通常有多個)和應用B(1個)進行 socket通訊,應用A必須知道應用B的ip地址(在應用A的配置文件中寫死的),這個時候就必須把應用B的ip設成固定ip(但是某些時候如更換路由

網路程式設計(InetAddress類、Socket和ServerSocket、實現客戶端和伺服器之間的雙向通訊

網路程式設計的底層是IO,通過IO將一臺計算機中的資料傳送到另一臺計算機中。傳送的時候,要知道接受方的地址,該地址即為IP地址。知道IP地址後即可進行傳送。A向B發訊息,訊息是發過去了,但是B要怎樣接受呢?因此定義了埠,B監聽了A所使用的埠。A發的訊息中含有埠號,當B接受到訊息時,知道了埠號

實現socket的服務和客戶端通訊

對學習過程中自己敲的一些關於socket有關的程式碼做了個簡單總結,在這分享一下,給有需要的同學借鑑一下。 什麼是socket? 網路上的兩個程式通過一個雙向的通訊連線實現資料的交換,這個連線的一端稱為一個socket。 建立網路通訊連線至少要一對埠號(socket)。socke

Java以GET和POST方式實現HTTP通訊

 此程式可以建立HTTP通訊,分別以GET和POST方式向WEB伺服器提交資訊,並接收WEB伺服器返回的響應。 import java.io.*; import java.net.*; public class s311 { public static void main(S