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("服务已启动...");
server.start(8844);
}
public void start(int port) throws Exception {
//配置服务端的NIO线程组
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new ServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128) //最大客户端连接数为128
.childOption(ChannelOption.SO_KEEPALIVE, true);
//绑定端口,同步等待成功
ChannelFuture f = b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
} finally {
//优雅退出,释放线程池资源
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
}
2
创建ServerHandler类来负责对网络事件进行读写操作
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()+"离开了");
}
}
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,它用于对网络事件进行读写操作,通常我们只需要关注channelRead和exceptionCaught方法。下面对这两个方法进行简单说明。
第30行做类型转换,将msg转换成Netty的ByteBuf对象。通过ByteBuf的readableBytes方法可以获取缓冲区可读的字节数,根据可读的字节数创建byte数组,通过ByteBuf的readBytes方法将缓冲区中的字节数组复制到新建的byte数组中,最后通过new String构造函数获取请求信息。这是对请求消息进行判断,如果是“QUERY TIME ORDER”则创建应答信息,通过ChannelHandlerContext的write方法异步发送应答消息给客户端。
第43行,当发生异常时,关闭ChannelHandlerContext,释放和ChannelHandlerContext相关联的句柄等资源。
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 ("连接服务器成功\r\n");
Thread threadReceive = new Thread(ReceiveMsg);
threadReceive.IsBackground = true;
threadReceive.Start();
}catch
{
Debug.Log ("连接服务器失败\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);
//区分是客户端来了,还是消息来了
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 ("服务器说:" + msg + "\r\n");
msg = "";
}
if (!string.IsNullOrEmpty(ip))
{
ip = "";
}
}
void OnApplicationQuit()
{
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
参考资料
<