Android实现服务端与客户端netty交互(windows)包括部分问题及解决方案

---------------2020-3-14初次记录

初入Netty,了解参考:跳转

服务端使用eclipse,客户端使用android studio3.5.2:

代码参考:跳转包括(环境搭建)

服务端客户端均在eclipse,代码参考:跳转

后期待修补(android studio测试可运行,但是我的netty版本以及as的SDK版本及真机测试API版本有问题,待修补)。

---------------2020-3-15更新

因为昨日在android测试的时候出现了很多问题,今天解决了挺多,在此记录一下问题与解决方案。

前提:

我的as版本3.5.2,compilesdkversion 8.0,targetsdkversion 8.0,compiletoolversion 29.0.2,客户端netty版本4.1.11,真机测试android 7& android9

 

1:在创建连接的代码处:group = new NioEventLoopGroup(); 报错:No class deffound error log/apache/loging/log4J2Logger.....

问题原因:因为当时我用的netty版本是4.5.x,总之比4.1.11版本高,我尝试import这个类,果然没有,我觉得是包的问题。

问题解决:重新导入了4.1.11版本的netty包,问题解决。

在此额外提一句,如果是as由原来的包更换的话,注意把之前的依赖项给remove,如果是通过maven-Gradle导入的包,现在的好像自动移除之前的依赖,问题可能会出现在你通过jar包添加的依赖!

2:纯属我的as问题:在activity的代码处:setContentView(R.layout.activity_sign); 报错:java.lang.ClassNotFoundException: Didn't find class "android.view.View$OnUnhandledKeyEventListener" on path: DexPathList[[zip file "/data/app/com.example.login_server-2/base.apk"],nativeLibraryDirectories=[/data/app/com.example.login_server-2/lib/arm64, /data/app/com.example.login_server-2/base.apk!/lib/arm64-v8a, /system/lib64, /vendor/lib64]]

问题原因:因为系统编译版本更新以后,编译工具都是29的了,而我的android真机还是7.0,API24所以对比起来差了很多,以前我跑这个真机从来每出现过。。。

问题解决:我用android9的真机测试了一下,把targetversion和compileversion改为28,tool还是29.0.2好歹还接近一点28,就没有这个问题了,对于这个问题的解决方案是忽视:事实上即使提醒了,这个问题至目前为止除了报错还没有出现其他问题,后期也考虑使用android9手机测试。如果你尝试将gradle中的targetversion和compileversion改为24,那不行,除非你的tool有低版本的。。。我最低的就是28.0了(哭泣! 而且谷歌那边好像要求targetversion最低26..

---------2020-3-17 我来更新这个问题啦,在昨晚上跑系统的时候一如既往地报这个错误(问题2),我突然注意到错误里面提到了AppcompatActivity,众所周知,activity要么extends AppcompatActivity要么extends activity,于是我怀疑是不是因为不能集成AppcompatActivity的原因,因为我一直继承的AppcompatActivity,只有单独使用button的on click方法时才考虑更换。--3-18 我又来了,如果你的activity里面有图片(drawable)那此解决方法无效。

解决方法:将activity的继承更改为Activity,就不再报这个错误!!!(也许仅适用于我的module...  maybe you can try it....

 

3:在一个activity使用netty连接上服务端后,在另一个activity获取之前连接的channel(来自自定义类--用于连接服务端,获取channel等等,但是获取到的channel为空,也就是没有连接???我的服务端显示已经连接上了!

问题原因:因为我在不同的activity中都创建了自定义类的对象,既然是不同对象,里面的类型值自然不一样,自然不能有B这个对象获取A这个对象之前保存的值!

问题解决:自定义了一个类,设置static channel值,连接上服务端后就setchannel,其他activity获取值也从这里面直接拿就行,测试可行,代码在后面有。

4:连接成功发送数据失败:1)注意你的结束符设置的是什么?发送的数据要以你设置的为准。2)如果你的测试代码里面连接之后就是发送信息,很有可能出现你还没连接上,就开始跑发送数据这块代码,我jio得可能因为子线程跑完在跑的同时,按顺序执行代码也在继续,就出现这个问题了!注意在连接之后再发送数据,或者直接在你的连接里面发数据也可以。

5:服务端返回信息给客户,客户获取并发送至activity:可以使用handle,突然想到一个问题,如果发送到其他普通类呢?emmmm待解决。

6:因为我在项目中加密了一些数据,加密后的数据包含换行符('\n')需要发到服务端,而我初始化的发送数据以换行符为结束符,这样我服务端就无法收到完整正确的数据了!

问题原因:自定义结束符为\n。

问题解决:修改结束符为$E$,貌似$是特殊字符一般不会在加密后的数据中出现!

7:activity中的AlertDialog定义后调用不弹出!

我的链接(单独开出来一个随笔嘿嘿嘿

 

 

我的代码(客户端),仅供参考:

nettyTcpThread:连接服务端

 

  1 package com.example.login_server.netty;
  2 
  3 import android.util.Log;
  4 
  5 import io.netty.bootstrap.Bootstrap;
  6 import io.netty.channel.Channel;
  7 import io.netty.channel.ChannelFuture;
  8 import io.netty.channel.ChannelOption;
  9 import io.netty.channel.EventLoopGroup;
 10 import io.netty.channel.nio.NioEventLoopGroup;
 11 import io.netty.channel.socket.nio.NioSocketChannel;
 12 
 13 /**
 14 *2020-3-15
 15 * by Zhang Liling
 16 **/
 17 public class nettyTcpThread {
 18     private String TAG = "nettyTcpClient";
 19     private String mIp = "XXX,XXX,XX,XX";  //  插入你的ip地址
 20     private int mPort = 7327;
 21 
 22     private Channel mChannel;
 23     private EventLoopGroup group;
 24 
 25     public void startConnect(){
 26         if (nettyChannelFuture.getIsConnect()){
 27             return;
 28         }
 29         group = new NioEventLoopGroup();
 30         try{
 31             Bootstrap clientBootStrap = new Bootstrap();
 32             clientBootStrap.group(group)
 33                     .channel(NioSocketChannel.class)
 34                     .option(ChannelOption.TCP_NODELAY,true)  //  屏蔽Nagle算法试图
 35                     .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,5000)
 36                     .handler(new ClientInitializer());
 37             ChannelFuture future = clientBootStrap.connect(mIp, mPort).sync();
 38             mChannel = future.channel();
 39             nettyChannelFuture.setChannel(mChannel);
 40             nettyChannelFuture.setGroup(group);
 41             nettyChannelFuture.setIsConnect(true);
 42             Log.i(TAG,"已连接到服务器!");
 43 
 44             mChannel.closeFuture().sync();
 45             Log.i(TAG,"已从服务器断开");
 46         }catch (InterruptedException e){
 47             e.printStackTrace();
 48         }finally {
 49             group.shutdownGracefully();
 50         }
 51     }
 52 
 53     //  发起连接&发送数据data
 54     public void startConnectSendData(String data){
 55         if (nettyChannelFuture.getIsConnect()){
 56             return;
 57         }
 58         group = new NioEventLoopGroup();
 59         try{
 60             Bootstrap clientBootStrap = new Bootstrap();
 61             clientBootStrap.group(group)
 62                     .channel(NioSocketChannel.class)
 63                     .option(ChannelOption.TCP_NODELAY,true)  //  屏蔽Nagle算法试图
 64                     .option(ChannelOption.CONNECT_TIMEOUT_MILLIS,5000)
 65                     .handler(new ClientInitializer());
 66             ChannelFuture future = clientBootStrap.connect(mIp, mPort).sync();
 67             mChannel = future.channel();
 68             nettyChannelFuture.setChannel(mChannel);
 69             nettyChannelFuture.setGroup(group);
 70             nettyChannelFuture.setIsConnect(true);
 71             Log.i(TAG,"已连接到服务器!");
 72             mChannel.writeAndFlush(data+"\n");
 73 
 74             mChannel.closeFuture().sync();
 75             Log.i(TAG,"已从服务器断开");
 76         }catch (InterruptedException e){
 77             e.printStackTrace();
 78         }finally {
 79             group.shutdownGracefully();
 80         }
 81     }
 82 
 83     public void sendMsg(Channel channel, final String data){
 84         if(channel != null){
 85             channel.writeAndFlush(data+"\n");
 86         }else{
 87             new Thread(){
 88                 @Override
 89                 public void run() {
 90                     startConnectSendData(data);
 91                 }
 92             }.start();
 93         }
 94     }
 95 
 96     public void disconnect(Channel channel){
 97         if(channel != null){
 98             channel.close();
 99             Log.e(TAG,"disconnect");
100             nettyChannelFuture.setIsConnect(false);
101         }else{
102             Log.i(TAG,"channel已断开连接");
103         }
104     }
105 
106 }
nettyTcpThread

 

ClientInitializer :设置channel参数

 1 package com.example.login_server.netty;
 2 
 3 import io.netty.channel.Channel;
 4 import io.netty.channel.ChannelInitializer;
 5 import io.netty.channel.ChannelPipeline;
 6 import io.netty.handler.codec.DelimiterBasedFrameDecoder;
 7 import io.netty.handler.codec.Delimiters;
 8 import io.netty.handler.codec.string.StringDecoder;
 9 import io.netty.handler.codec.string.StringEncoder;
10 import io.netty.util.CharsetUtil;
11 /**
12  *2020-3-15
13  * by Zhang Liling
14  **/
15 public class ClientInitializer extends ChannelInitializer {
16     @Override
17     protected void initChannel(Channel ch) throws Exception {
18         ChannelPipeline pipeline = ch.pipeline();
19         pipeline
20                 .addLast("framer",new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()))
21                 .addLast("decoder",new StringDecoder(CharsetUtil.UTF_8))
22                 .addLast("encoder",new StringEncoder(CharsetUtil.UTF_8))
23                 .addLast("handler",new EchoClientHandler());
24     }
25 }
ClientInitializer

 EchoClientHandler:处理返回数据

 1 package com.example.login_server.netty;
 2 
 3 import android.os.Bundle;
 4 import android.os.Message;
 5 import android.util.Log;
 6 
 7 import com.example.login_server.loginInfo.MainActivity;
 8 
 9 import io.netty.channel.ChannelHandlerContext;
10 import io.netty.channel.SimpleChannelInboundHandler;
11 /**
12  *2020-3-15
13  * by Zhang Liling
14  **/
15 public class EchoClientHandler extends SimpleChannelInboundHandler<String> {
16     private String TAG = "EchoClientHandler";
17     @Override
18     public void channelActive(ChannelHandlerContext ctx) throws Exception {
19         super.channelActive(ctx);
20     }
21 
22     @Override
23     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
24         super.channelInactive(ctx);
25     }
26 
27     private String getmsg(String data,String msg){
28         String getmsg = null;
29         String[] data0 = data.split(msg+"=");
30         if(data0!=null && data0.length > 1){
31             String[] data1 = data0[1].split(";");
32             getmsg = data1[0];
33         }
34         return getmsg;
35     }
36 
37     @Override
38     protected void channelRead0(ChannelHandlerContext channelHandlerContext, String data) throws Exception {
39         //  处理data
40         manageData(data);
41 
42         Log.i(TAG,"received msg from server:" + data);
43     }
44 
45     private void manageData(String data) {
46         String req="";
47         req = getmsg(data,"res");
48         if(req.equals("login")){
49             String myname = "";
50             myname = getmsg(data,"myname");
51             Message message = new Message();
52             message.what= MainActivity.RECNAME_LOGIN;
53             Bundle bundle = new Bundle();
54             bundle.putString("msg",myname);
55             message.setData(bundle);
56             MainActivity.getMainActivity().getMsghandler().sendMessage(message);
57         }else if(req.equals("loginmyinfo")){
58             Message message = new Message();
59             message.what= MainActivity.RECINFO_LOGIN;
60             Bundle bundle = new Bundle();
61             bundle.putString("pubkey",getmsg(data,"pubkey"));
62             bundle.putString("seckey",getmsg(data,"seckey"));
63             message.setData(bundle);
64             MainActivity.getMainActivity().getMsghandler().sendMessage(message);
65 
66         }
67     }
68 
69     @Override
70     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
71         cause.printStackTrace();
72         ctx.close();
73     }
74 }
EchoClientHandler

 nettyChannelFuture:存储变量供其他类连接使用

 1 package com.example.login_server.netty;
 2 
 3 import io.netty.channel.Channel;
 4 import io.netty.channel.EventLoopGroup;
 5 /**
 6  *2020-3-15
 7  * by Zhang Liling
 8  **/
 9 public class nettyChannelFuture {
10     private static Channel mchannel;
11     private static EventLoopGroup mgroup;
12     private static boolean misConnect;
13 
14     public static void setIsConnect(boolean isConnect) {
15         misConnect = isConnect;
16     }
17 
18     public static boolean getIsConnect() {
19         return misConnect;
20     }
21 
22     public static void setGroup(EventLoopGroup group) {
23         mgroup = group;
24     }
25 
26     public static void setChannel(Channel channel) {
27         mchannel = channel;
28     }
29 
30     public static Channel getChannel(){
31         return mchannel;
32     }
33 
34     public static EventLoopGroup getGroup(){
35         return mgroup;
36     }
37 }
nettyChannelFuture

 

 

 

T

posted @ 2020-03-14 18:18  achived  阅读(1928)  评论(0编辑  收藏  举报