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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM