基于netty 的android Socket 聊天室客户端

本文介绍如何在Android应用中使用Netty解决Socket通信的沾包问题,实现聊天室客户端。由于常规的Socket IO阻塞导致数据错误,作者转向使用Netty,并在缺少Android相关资料的情况下自行研发。提供了MainActivity.java的代码示例,欢迎大家交流。
摘要由CSDN通过智能技术生成

公司最近在开发一个移动端的聊天室,c#写的服务端。android 和ios 的客户端,这里用到的socket 通讯,但是socket 的io阻塞导致数据沾包,里一个小伙写了一个解决沾包的问题,但是我看了不是太理想,只有这个项目可以使用,换了其他项目就不能用了。偶然发现netty 这个东西。网上关于这个的资料不多,都是服务端的,android 这边几乎没有发现有用的资料。然后自己写了一个,现在贴出来大家看看,有问题可以交流下。

Email : ngh8897@163.com

废话不多说,直接上代码

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



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值