文档章节

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

开源中国首席院长
 开源中国首席院长
发布于 2015/06/09 14:56
字数 784
阅读 779
收藏 1

废话不多说,直接上代码

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();
        }
    }
}

MyClientHandler.java  

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);
    }

}

MyClientInitializer.java

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

© 著作权归作者所有

开源中国首席院长
粉丝 8
博文 5
码字总数 3075
作品 0
洛阳
Android工程师
私信 提问
加载中

评论(2)

yulinxx
yulinxx
http://www.cokco.cn/thread-41697-1-1.html
yulinxx
yulinxx
崩溃

http://www.2cto.com/kf/201502/376966.html
这什么关系
【转】Android 基于Socket的聊天室

原文 Socket是TCP/IP协议上的一种通信,在通信的两端各建立一个Socket,从而在通信的两端之间形成网络虚拟链路。一旦建立了虚拟的网络链路,两端的程序就可以通过虚拟链路进行通信。 Client...

长平狐
2012/06/28
7.5K
5
android实现简单的聊天室

先说一下流程。首先是建立一个java工程,并创建两个java类,一个用于接收到客户端的连接,并把连接添加list中,第二类实现线程runnable接口,专门用来接收发送客户发送的信息。其次,建立and...

wuwulh
2012/11/09
0
2
Android与MINA2、Netty4的跨平台UDP双向通信实战

概述 本文演示的是一个Android客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo。 当前由于NIO框架的流行,使得开发大并发、高性能的互联网服务端成为可能。...

JackJiang-
2016/06/30
804
1
Android 底层 socket 如何封装通信呢?

之前没有写过android中基于TCP和UDP的数据访问,不知道api该如何设计呢? android中用bio多一些还是nio多一些呢? netty框架在android中用的多吗?还是直接用socket写? socket有无工具类呢?...

铂金蛋蛋
2015/05/03
1K
2
netty推送后,手机端收到的数据不正确

在服务器上使用的是netty,在android客户端上我使用的就是普通的socket 通过客户端给服务器发送心跳并保持长连接,这点没问题,每次服务器返回的心跳应答协议也都正确,可以正常解包解析。 ...

Aberic
2014/11/21
995
10

没有更多内容

加载失败,请刷新页面

加载更多

springboot+jpa 错误信息org.springframework.beans.factory.BeanCreationException

报错信息 org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/a......

冥焱
22分钟前
1
0
威胁快报|新兴挖矿团伙借助shodan作恶,非web应用安全再鸣警钟

近日,阿里云安全发现了一个使用未授权访问漏洞部署恶意Docker镜像进行挖矿的僵尸网络团伙。我们给这一团伙取名为Xulu,因为该团伙使用这个字符串作为挖矿时的用户名。 Xulu并不是第一个攻击...

迷你芊宝宝
29分钟前
2
0
十大经典排序算法动画与解析

排序算法是《数据结构与算法》中最基本的算法之一。 排序算法可以分为内部排序和外部排序。 内部排序是数据记录在内存中进行排序。 而外部排序是因排序的数据很大,一次不能容纳全部的排序记...

夜黑人模糊灬
33分钟前
4
0
7. java枚举

1. 枚举是什么 有的时候一个类的对象是有限且固定的,这种情况下我们使用枚举类就比较方便 2. 为什么不用静态常量来替代枚举类呢? 3. 常用方式 3.1 方式1 枚举类: package cn.ali.tencent...

20190513
34分钟前
1
0
elasticsearch – 弹性搜索:“Term”,“Match Phrase”和“Query String”之间的差异

术语查询匹配单个术语,因为它是:不分析值。 所以,它不必根据你索引的情况而降低。 如果您在索引时间提供Bennett并且未分析该值,则以下查询将不返回任何内容: { "query": { "te...

xiaomin0322
40分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部