亚洲欧美日韩综合系列在线_91精品人妻一区二区_欧美大肥婆一级特大AA片_九色91视频免费观看_亚洲综合国产精品_av中文字幕在线不卡_久久精品色综合网_看黄色视频的软件_无卡无码高清中文字幕码2024_亚洲欧美日韩天堂网

【Netty4.x】Unity客戶端與Netty服務(wù)器的網(wǎng)絡(luò)通信(一)

來源:會編程的小毛驢 發(fā)布時間:2018-11-21 15:49:40 閱讀量:1171

一、我的開發(fā)環(huán)境

eclipse-jee-indigo-SR2-win32-x86_64

JDK1.7

windows-64

netty-all-4.1.1.Final-sources 下載地址:http://netty.io/ ,從【Downloads】選擇下載netty-all-4.1.1.Final-sources。

創(chuàng)建一個java工程,選中項目右鍵Properties->Java Build Path->Add External JARS->將netty-all-4.1.1.Final.jar包導(dǎo)入到項目中

二  、Netty服務(wù)器端開發(fā)

   2.1代碼示例

1 創(chuàng)建服務(wù)啟動類HttpServer,既然作為服務(wù)器它肯定和tomcat服務(wù)器一樣有個開關(guān)來開啟/關(guān)閉服務(wù)器,可以在類中看到有個main函數(shù)。對的,它的啟動方式就是右鍵->Run As->Java Application

package com.lll.game;

 

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

 

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;

 

public class HttpServer {

    private static Log log = LogFactory.getLog(HttpServer.class);

    

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

        HttpServer server = new HttpServer();

        log.info("服務(wù)已啟動...");

        server.start(8844);

    }

    

    public void start(int port) throws Exception {

    //配置服務(wù)端的NIO線程組

        EventLoopGroup bossGroup = new NioEventLoopGroup();

        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {

            ServerBootstrap b = new ServerBootstrap();

            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)

                    .childHandler(new ChannelInitializer<SocketChannel>() {

                                @Override

                                public void initChannel(SocketChannel ch) throws Exception {

                                ch.pipeline().addLast(new ServerHandler());

                                }

                            }).option(ChannelOption.SO_BACKLOG, 128) //最大客戶端連接數(shù)為128

                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            //綁定端口,同步等待成功

            ChannelFuture f = b.bind(port).sync();

            //等待服務(wù)端監(jiān)聽端口關(guān)閉

            f.channel().closeFuture().sync();

        } finally {

        //優(yōu)雅退出,釋放線程池資源

            workerGroup.shutdownGracefully();

            bossGroup.shutdownGracefully();

        }

    }

}

2創(chuàng)建ServerHandler類來負責(zé)對網(wǎng)絡(luò)事件進行讀寫操作

package com.lll.game;

 

import io.netty.channel.ChannelHandlerAdapter;

import io.netty.channel.ChannelHandlerContext;

 

public class ServerHandler extends ChannelHandlerAdapter{

@Override

public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

super.handlerAdded(ctx);

System.out.println(ctx.channel().id()+"進來了");

}

@Override

public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

super.handlerRemoved(ctx);

System.out.println(ctx.channel().id()+"離開了");

}

}


提示:本書作者使用的是netty是用的5.0,我在官方下載的時候只找到4.x包(據(jù)說5.0好像已經(jīng)被官方廢棄了)。2個版本相比較,不同版本ChannelHandler申明的方法不一樣!!

   2.2 Netty5.x與4.x代碼上的差異

  在4.x中,ChannelHandlerAdapter里的channelRead方法在ChannelInboundHandlerAdapter抽象類中,同5.X一樣ChannelInboundHandlerAdapter也是基于ChannelHandler接口。這樣用戶可以方便地進行業(yè)務(wù)邏輯定制,例如:打印日志、統(tǒng)一封裝異常信息、性能統(tǒng)計和消息編碼解碼等。

ChannelInboundHandlerAdapter的UML圖如下:



   2.3 4.x ServerHandler類

package com.game.lll.net;

 

import java.util.Date;

 

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

 

import io.netty.buffer.ByteBuf;

import io.netty.buffer.Unpooled;

import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.ChannelInboundHandlerAdapter;

 

public class ServerHandler extends ChannelInboundHandlerAdapter{

private static Log log = LogFactory.getLog(ServerHandler.class);

@Override

public void handlerAdded(ChannelHandlerContext ctx) throws Exception {

super.handlerAdded(ctx);

System.out.println(ctx.channel().id()+"進來了");

}

@Override

public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

super.handlerRemoved(ctx);

System.out.println(ctx.channel().id()+"離開了");

}

@Override

public void channelRead(ChannelHandlerContext ctx, Object msg)

throws Exception {

ByteBuf buf = (ByteBuf)msg;

byte[] req = new byte[buf.readableBytes()];

buf.readBytes(req);

String body = new String(req,"UTF-8");

log.info(req);

String currentTime = "QUERY TIME ORDER".equalsIgnoreCase(body)?

new Date(System.currentTimeMillis()).toString():"BAD ORDER";

ByteBuf resp = Unpooled.copiedBuffer(currentTime.getBytes());

ctx.write(resp);

}

@Override

public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

ctx.flush();

}

@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)

throws Exception {

// TODO Auto-generated method stub

ctx.close();

}

}

  ServerHandler繼承自ChannelInboundHandlerAdapter,它用于對網(wǎng)絡(luò)事件進行讀寫操作,通常我們只需要關(guān)注channelRead和exceptionCaught方法。下面對這兩個方法進行簡單說明。

   2.3.1 channelRead()操作

  第30行做類型轉(zhuǎn)換,將msg轉(zhuǎn)換成Netty的ByteBuf對象。通過ByteBuf的readableBytes方法可以獲取緩沖區(qū)可讀的字節(jié)數(shù),根據(jù)可讀的字節(jié)數(shù)創(chuàng)建byte數(shù)組,通過ByteBuf的readBytes方法將緩沖區(qū)中的字節(jié)數(shù)組復(fù)制到新建的byte數(shù)組中,最后通過new String構(gòu)造函數(shù)獲取請求信息。這是對請求消息進行判斷,如果是“QUERY TIME ORDER”則創(chuàng)建應(yīng)答信息,通過ChannelHandlerContext的write方法異步發(fā)送應(yīng)答消息給客戶端。


   2.3.2 exceptionCaught()操作

  第43行,當發(fā)生異常時,關(guān)閉ChannelHandlerContext,釋放和ChannelHandlerContext相關(guān)聯(lián)的句柄等資源。


三  、Unity客戶端開發(fā)

   3.1 代碼示例

using System.Net.Sockets;

using System.Text;

using System.Threading;

using UnityEngine;

using UnityEngine.UI;

using System.Collections.Generic;

 

public class HttpClient : MonoBehaviour

{

private const string IP = "127.0.0.1";

private const int PORT = 8844;

 

public UILabel userName;

public UILabel password;

 

private Socket client;

private string msg,ip;

 

public void start()

{

try {

client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

client.Connect(IP, PORT);

Debug.Log ("連接服務(wù)器成功\r\n");

 

Thread threadReceive = new Thread(ReceiveMsg);

threadReceive.IsBackground = true;

threadReceive.Start();

}catch

{

Debug.Log ("連接服務(wù)器失敗\r\n");

}

}

 

public void Send()

{

if(client == null)

{

start ();

}

 

byte[] buffer = Encoding.UTF8.GetBytes("userName:"+userName.text+" password"+password.text);

client.Send(buffer);

 

}

 

private void ReceiveMsg()

{

byte[] buffer = new byte[1024 * 1024];

int len = 0;

while (true)

{

len = client.Receive(buffer);

//區(qū)分是客戶端來了,還是消息來了

if (buffer[0] == 1)//客戶端

{

ip=Encoding.UTF8.GetString(buffer, 1, len - 1);

}else//文本消息

{

msg = Encoding.UTF8.GetString(buffer, 1, len-1);

}

}

print (msg);

}

 

void Update()

{

if (!string.IsNullOrEmpty(msg))

{

Debug.Log ("服務(wù)器說:" + msg + "\r\n");

msg = "";

}

if (!string.IsNullOrEmpty(ip))

{

 

ip = "";

}

}

 

void OnApplicationQuit()

{

client.Shutdown(SocketShutdown.Both);

client.Close();

}

}

   3.2 控制臺

   3.2.1 啟動服務(wù)器端



   3.2.2 啟動客戶端



   3.2.3 控制臺(服務(wù)器)



   3.2.4 控制臺(客戶端)


--------------------- 



分享:
評論:
你還沒有登錄,請先