Android Mina 与Linux TCP通信-1

这是一个什么系列

最近做了一个IM的项目,客户端是Android,服务器是Linux,不算什么新颖,但是我在爬坑的过程中总结的问题能够给你一个知道,使你迅速定位问题,当然我只是一个研究生,如果你是大牛请多指教。
服务器的文章写过一篇,但是一直没有时间继续写,最近有需要写客户端还有就是我在做这个项目的一些思考。最近加把劲争取每周都能更新一篇吧。

写在前面

之前用Linux写过一个服务器,有这篇博客
https://github.com/wsrspirit/Linux_Server_Reactor
现在开始接手Android。
通信协议基本已经确定,通信协议会单独写博客,这个需要我完完全全搞定通信再写,目前也在摸着石头过河。
下面就是通信了。Android的TCP框架有两个框架可以选择Netty和Mina,为此我还专门看过博客,虽然并没有什么实质性进展。。大家对Netty比较看好,虽然这两个都是一个作者,于是使用Netty,资料其少无比!!英文的也不多。。于是弃坑了,Android Mina还是较多的。没办法赶进度,不能慢慢啃了。。

配置

Mina开发非常简单,首先是包

compile 'org.slf4j:slf4j-android:1.7.7'
compile 'org.apache.mina:mina-core:2.0.4'

如果你出现了Failed to load class “org.slf4j.impl.StaticLoggerBinder”说明你没有加载slf4j的依赖。但是如果你gradle编译出现了依赖重复,

com.android.dex.DexException: Multiple dex files define Lorg/slf4j/ILoggerFactory;

下面的网站帮助你~
http://blog.csdn.net/hyr83960944/article/details/41825087

大端小端?

这个是要最先考虑的,Linux没什么说的肯定是小端了,Java和网络流是大端,这就需要对应了。写个测试
Java:

boolean b = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;

C测试的思路就是一个union中一个int和char然后int=1 判断char
Linux需要使用小端数据,所以网络数据需要转换。ntohl是Linux提供的方法
同时网络数据需要时大端数据,Linux在发送的时候还需要再转换。htonl是Linux提供的方法
http://linux.die.net/man/3/htons

如果你传了一个很小的id,结果对面解析成了很大的数字,那么基本就是大端小端的问题了。这个问题会单独写一篇博客的。

写代码

然后就可以愉快的编代码了,Mina非常简单
首先写个Thread

public class MinaThread implements Runnable{
    private IoSession session = null;

    @Override
    public void run() {
        // TODO Auto-generated method stub
        Log.d("TEST", "客户端链接开始...");
        IoConnector connector = new NioSocketConnector();

        //设置链接超时时间
        connector.setConnectTimeoutMillis(3000);
        //添加过滤器
        connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory()));
        connector.setHandler(new MinaClientHandler());

        try{
            ConnectFuture future = connector.connect(new InetSocketAddress(PathUtil.IP,PathUtil.PORT));//创建链接
            future.awaitUninterruptibly();// 等待连接创建完成
            session = future.getSession();//获得session
            MessageEntity messageEntity = new MessageEntity();
            messageEntity.setDesId(PackageFlag.REGISTE_USER);
            Gson gson = new Gson();
            session.write(gson.toJson(messageEntity));
        }catch (Exception e){
            Log.d("TEST","客户端链接异常...");
            e.printStackTrace();
        }

        CloseFuture closeFuture = session.getCloseFuture();
        closeFuture.awaitUninterruptibly();
//                session.getCloseFuture().awaitUninterruptibly();//等待连接断开
        Log.d("TEST", "客户端断开...");
        connector.dispose();
    }

}

然后再写个handler

public class MinaClientHandler extends IoHandlerAdapter {
    private static final String TAG = "IM_Client_Core";
    @Override
    public void exceptionCaught(IoSession session, Throwable cause)
            throws Exception {
        Log.d("TEST", "客户端发生异常");
        super.exceptionCaught(session, cause);
    }

    @Override
    public void sessionCreated(IoSession session) throws Exception {
        Log.d(TAG,"sessionCreated");
        super.sessionCreated(session);
    }

    @Override
    public void sessionOpened(IoSession session) throws Exception {
        Log.d(TAG,"sessionOpened");
        super.sessionOpened(session);
    }

    @Override
    public void sessionClosed(IoSession session) throws Exception {
        Log.d(TAG,"sessionClosed");
        super.sessionClosed(session);
    }

    @Override
    public void messageReceived(IoSession session, Object message)
            throws Exception {

        String msg = message.toString();
        System.out.println("客户端接收到的信息为:" + msg);
        Log.d("TEST","客户端接收到的信息为:" + msg);
        super.messageReceived(session, message);
    }

    @Override
    public void messageSent(IoSession session, Object message) throws Exception {
        // TODO Auto-generated method stub
        super.messageSent(session, message);
    }
}

App发送数据没什么问题,服务器收到了,但是没想到客户端收不到服务器的回复,也就是MinaClientHandler的messageReceived没有执行!奇怪的是sessionCreated和sessionOpened也不打印日志,我一下慌了,以为Log没有配置正确,查之后slf4j是一个接口型日志,而Android自带Log的实现,应该不是这里的问题,关键是没有execption啊!这个问题解决的有点呵呵,我把魅族换成了小米测试,出现了Log消息。。沃日!

再抓包,发现包是发过去了,抓包这个自己搜一个用的顺手的就好了~

再搜索!于是找到了一个靠谱的
http://stackoverflow.com/questions/2735370/apache-mina-nio-connector-help

but the TextLineDecoder created by TextLineCodecFactory will be looking for (by default) a ‘\r’ (0x0d) or ‘\n’ (0x0a) to end the line and generate the completed message to be handled by your IoHandlerAdapter.

这。。。居然是这么flush缓冲区的,我在Iosession方法中没找到flush方法啊,好吧,于是在服务器返回数据中加入’\n’
于是又有了:Caused by: java.nio.charset.MalformedInputException并且还是没有收到信息,查
http://my.oschina.net/gs80140/blog/209700
我想大概意思我懂了,就是应该是在’\n’和包内容结束中间有空隙(我确实留了空袭),于是直接在包最后紧贴着加上’\n’。ok终于收到了。

优化

这个问题还是因为使用了Mina的Encoder类,找不到结束位置,所以还是自己重写这个方法好一些,官网的例子如下~
https://mina.apache.org/mina-project/userguide/ch9-codec-filter/ch9-codec-filter.html

这只是系列的第一个博客,希望能有机会把客户端和服务器都写的好一点,服务器已经上传github。服务器的博客也一直没有时间更新。。。最近好忙,心情也不好 = =b(投了百度的实习居然连笔试都不给。。悲剧)
https://github.com/wsrspirit/Linux_Server_Reactor

愿一切顺利吧

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值