NO IMAGE

公司最近在開發一個移動端的聊天室,c#寫的服務端。android 和ios 的客戶端,這裡用到的socket 通訊,但是socket 的io阻塞導致資料沾包,裡一個小夥寫了一個解決沾包的問題,但是我看了不是太理想,只有這個專案可以使用,換了其他專案就不能用了。偶然發現netty 這個東西。網上關於這個的資料不多,都是服務端的,android 這邊幾乎沒有發現有用的資料。然後自己寫了一個,現在貼出來大家看看,有問題可以交流下。

Email : [email protected]

廢話不多說,直接上程式碼

MainActivity.java    主頁面

import java.net.InetSocketAddress;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity {
private static final String TAG = "TAG";
public static int MSG_REC = 0xabc;
public static final String HOST = "192.168.2.219";
public static int PORT = 9103;
private NioEventLoopGroup group;
private Channel mChannel;
private ChannelFuture cf;
private static Context context;
private TextView tv;
private Button btn;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == MSG_REC) {
Toast.makeText(context, msg.obj.toString(), 0).show();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
connected();
tv = (TextView) findViewById(R.id.iv);
btn = (Button) findViewById(R.id.btn);
btn.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(MainActivity.this));
//如果沒有資料,這個可以註釋看看
bootstrap.option(ChannelOption.SO_KEEPALIVE, true);  
bootstrap.option(ChannelOption.TCP_NODELAY, true);
// 連線到本地的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("我是android客戶端");
mChannel.read();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (group != null) {
group.shutdownGracefully();
}
}
}

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class MyClientHandler extends SimpleChannelInboundHandler<String> {
private Context context;
public MyClientHandler(Context context) {
this.context = context;
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg)
throws Exception {
Log.d("MyHelloClientHandler", "channelRead0->msg="   msg);
}
@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);
}
}

import android.content.Context;
import android.os.Handler;
import android.util.Log;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;
public class MyClientInitializer extends ChannelInitializer<SocketChannel> {
private Context context;
public MyClientInitializer(Context ctx) {
this.context = ctx;
}
@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));
}
@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);
}
}

既然是網路通訊,肯定得加上網路許可權

<uses-permission android:name="android.permission.INTERNET" />

要加上netty4  的jar   

下載地址:http://netty.io/downloads.html