天天看點

[Android初級]android與netty4初體驗

    部落客曾經對netty4的helloword很感興趣,也曾單純的寫過一個小小的聊天室java代碼,現在重新來看看,浏覽了這位牛人的部落格 點選去看看

    我覺得受益匪淺,故拿來分享。

     這次是在android上使用netty作為用戶端,來與服務端互相通訊的小事例,純粹的helloworld,效果就是在android程式中發送一個消息到服務端,然後服務端也回一個消息給用戶端,很簡單的demo,.大牛看了可不要吐槽啊!

1.demo結構

[Android初級]android與netty4初體驗

2.服務端代碼:

Server.java

package org.jan.netty.demo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class MyHelloServer {

	private static final int PORT = 7878;

	public static void main(String[] args) {
		EventLoopGroup parentGroup = new NioEventLoopGroup();
		EventLoopGroup childrenGroup = new NioEventLoopGroup();
		try {
			ServerBootstrap serverBootstrap = new ServerBootstrap();
			serverBootstrap.group(parentGroup, childrenGroup);
			serverBootstrap.channel(NioServerSocketChannel.class);
			//添加工作線程
			serverBootstrap.childHandler(new MyHelloServerInitializer());
			// 伺服器綁定端口監聽
			ChannelFuture cf = serverBootstrap.bind(PORT).sync();
			// 監聽伺服器關閉監聽
			cf.channel().closeFuture().sync();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			parentGroup.shutdownGracefully();
			childrenGroup.shutdownGracefully();
		}
	}
}
           

MyHelloServerHandler.java

package org.jan.netty.demo;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

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

public class MyHelloServerHanler extends SimpleChannelInboundHandler<String> {

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, String msg)
			throws Exception {
		String recStr = new String(msg.getBytes(), Charset.forName("UTF-8"));
		//收到消息直接列印輸出
		System.out.println(ctx.channel().remoteAddress()+" say :"+recStr);
		//傳回用戶端 
		ctx.writeAndFlush("Received your message!\n");
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("RamoteAddress: "+ctx.channel().remoteAddress()+" active!");
//		ctx.writeAndFlush("Welcome to " + InetAddress.getLocalHost().getHostName() + "'s service!\n");
		ctx.writeAndFlush("我是服務端,我是服務端!\n");
		super.channelActive(ctx);
	}
}
           

3.android用戶端代碼:

/**
 * demo主界面:隻有一個按鈕發送消息
 * @author jan
 */
public class ClientActivity extends Activity {
	private static final String TAG = "MainActivity";
	private static Context context;
	public static int MSG_REC=0xabc;
	public static int PORT = 7878;
	public static final String HOST = "192.168.50.110";
	private NioEventLoopGroup group;
	private Button sendButton;
	private Channel mChannel;
	private ChannelFuture cf;
	private Handler mHandler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			if(msg.what==MSG_REC){
				Toast.makeText(context, msg.obj.toString(), 1000).show();
			}
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		context = this;
		connected();
		sendButton = (Button) findViewById(R.id.netty_send_button);
		sendButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				sendMessage();
			}
		});
	}

	// 連接配接到Socket服務端
	private void connected() {
		new Thread() {
			@Override
			public void run() {
				group = new NioEventLoopGroup();
				try {
					// Client服務啟動器 3.x的ClientBootstrap
					// 改為Bootstrap,且構造函數變化很大,這裡用無參構造。
					Bootstrap bootstrap = new Bootstrap();
					// 指定EventLoopGroup
					bootstrap.group(group);
					// 指定channel類型
					bootstrap.channel(NioSocketChannel.class);
					// 指定Handler
					bootstrap.handler(new MyClientInitializer(context,mHandler));
					bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
					bootstrap.option(ChannelOption.TCP_NODELAY, true);
					bootstrap.option(ChannelOption.SO_TIMEOUT, 5000);
					// 連接配接到本地的7878端口的服務端
					cf = bootstrap.connect(new InetSocketAddress(
							HOST, PORT));
					mChannel = cf.sync().channel();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}.start();
	}
	//發送資料
	private void sendMessage() {
		mHandler.post(new Runnable() {
			@Override
			public void run() {
				try {
					Log.i(TAG, "mChannel.write sth & " + mChannel.isOpen());
					mChannel.writeAndFlush("hello,this message is from client.\r\n");
					mChannel.read();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		if (group != null) {
			group.shutdownGracefully();
		}
	}

}
           

4.用戶端中 bootstrap的初始化類MyClientInitializer.java

public class MyClientInitializer extends ChannelInitializer<SocketChannel> {
	private Context context;
	private Handler handler;
	public MyClientInitializer(Context ctx,Handler handler){
		this.context = ctx;
		this.handler = handler;
	}
	
	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		ChannelPipeline pipeline = ch.pipeline();
		/**
		 * 這個地方的必須和服務端對應上。否則無法正常解碼和編碼
		 */
		pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
		pipeline.addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));
		pipeline.addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));
		//用戶端的邏輯
		pipeline.addLast("handler",new MyClientHandler(context,handler));
	}

	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {
		System.out.println("---channelRead--- msg="+msg);
		super.channelRead(ctx, msg);
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		System.out.println("---channelReadComplete---");
		super.channelReadComplete(ctx);
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		Log.i("MyClientInitializer","---channelActive---");
		super.channelActive(ctx);
	}
	
}
           

5.對應的資料處理類 ,沒有什麼新鮮性的東西哦。MyClientHandler.java

public class MyClientHandler extends SimpleChannelInboundHandler<String> {
	private Context ctx;
	private Handler handler;

	public MyClientHandler(Context context, Handler handler) {
		this.ctx = context;
		this.handler = handler;
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, String msg)
			throws Exception {
		Log.d("MyHelloClientHandler", "channelRead0->msg="+msg);
		Message m = new Message();
		m.what = ClientActivity.MSG_REC;
		m.obj = msg;
		handler.sendMessage(m);
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("Client active");
		super.channelActive(ctx);
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
		System.out.println("Client close ");
		super.channelInactive(ctx);
	}

}
           

實作效果:

[Android初級]android與netty4初體驗

去下載下傳demo