安卓socket实例(三)实现OPN、DIR操作,优化架构(1)

String cmdBody = splitCmd[1];

ArrayList msgBackList = new ArrayList();

if (cmdHead.equals(“dir”)) {
msgBackList = new DIR().exe(cmdBody);
msgBackList.add(0,“dir”);//增加正常执行返回的代码"ok"
return msgBackList;
}
if (cmdHead.equals(“opn”)) {
msgBackList = new OPN().exe(cmdBody); // 待实现的打开文件命令
msgBackList.add(0,“opn”);//增加正常执行返回的代码"ok"
return msgBackList;
}
//… 继续判断其他命令

if(msgBackList.size()==0){
msgBackList.add(0,“无效命令:”+cmd);//msgBackList长度为0,说明命令没有得到解析和执行
}

throw new Exception(“无效命令!”);//若代码正确执行了,就return了,不会执行到这里,执行到这说明出错了
}

public static String[] splitCmd(String cmd) throws Exception {
String[] cmdout = null;
int splitIdx = cmd.indexOf(“:”);
System.out.println("服务端接受命令: " + cmd);
if (splitIdx < 1) {
throw new Exception("非法命令: " + cmd);// 抛出异常
} else {
cmdout = new String[2];
String cmdHead = cmd.substring(0, splitIdx);
String cmdBody = cmd.substring(splitIdx + 1);
cmdout[0] = cmdHead.toLowerCase();//按小写处理字符串
cmdout[1] = cmdBody;
}
return cmdout;

}
}

ServerSocket01.java更改如下

package lrz.server;

import lrz.tool.Operator;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Enumeration;

public class ServerSocket01 {

int port = 8019;// 自定义一个端口,端口号尽可能挑选一些不被其他服务占用的端口,祥见http://blog.csdn.net/hsj521li/article/details/7678880
ArrayList msgBackList;

public ServerSocket01() {
// TODO Auto-generated constructor stub
}

public ServerSocket01(int port) {
super();
this.port = port;
}
private void printLocalIp(ServerSocket serverSocket) {// 枚举打印服务端的IP
try {
System.out.println(“服务端命令端口prot=” + serverSocket.getLocalPort());
Enumeration interfaces = null;
interfaces = NetworkInterface.getNetworkInterfaces();
while (interfaces.hasMoreElements()) {
NetworkInterface ni = interfaces.nextElement();
Enumeration addresss = ni.getInetAddresses();
while (addresss.hasMoreElements()) {
InetAddress nextElement = addresss.nextElement();
String hostAddress = nextElement.getHostAddress();
System.out.println(“本机IP地址为:” + hostAddress);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}

public void work() throws Exception {
// 注意:由于Socket的工作是阻塞式,Android端Socket的工作必须在新的线程中实现,若在UI主线程中工作会报错
ServerSocket serverSocket = new ServerSocket(port);
printLocalIp(serverSocket);

while (true) {// 无限循环
System.out.println(“=“);
System.out.println(”| Waiting client to connect…|“);
System.out.println(”
=”);

Socket socket = serverSocket.accept();// 阻塞式
System.out.println("连接请求来自: "+ socket.getRemoteSocketAddress().toString());
try{
getAndDealCmd(socket);
} catch (Exception e) {
cmdFail(e.toString());
}
SocketMsg.writeBackMsg(socket,msgBackList);

System.out.println(“…输出流…”);
msgBackList.forEach(s -> System.out.println(s));
System.out.println(“…”);

socket.close();
System.out.println(“本次Socket服务结束”);
System.out.println(“---------------------------------”);
System.out.println(“---------------------------------”);

}

}

public void getAndDealCmd(Socket socket) throws Exception {

ArrayList cmdList = SocketMsg.readSocketMsg(socket);
if(cmdList.size()==0){
cmdFail(“Cmd输入为空. “);//若命令长度0行,则返回错误信息
}
System.out.println(”…输入流…”);
cmdList.forEach(s -> System.out.println(s));
System.out.println(“…”);

if(cmdList.size()==1){
msgBackList=Operator.exeCmd(cmdList.get(0));// Operator类为自定义类,实现命令头部和主体的分离和调用判断
}else{
// msgBackList=MultiOperator.exeCmd(cmdList);//待实现的,支持多条命令串行执行
}

}

private void cmdFail(String e) {
msgBackList.clear();//
String nu=“java.lang.NullPointerException”;
if(e.equals(nu)){
e=“目标不存在”;
}
msgBackList.add(e);//将出错信息放入msgBackList
}

/**

  • @param args
    */
    public static void main(String[] args) throws Exception {
    new ServerSocket01().work();
    }

}

安卓端更新

SocketClient.java添加对服务端返回命令头部命令类型的解析,设置handler返回的type,例如SERVER_MSG_DIR,借此在MainActivity.java得以让handler监听到的数据根据不同的命令返回结果进行不同的操作。

package com.example.android_app;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.ArrayList;

public class SocketClient {
public static int SERVER_MSG_OK=0;//用于发送给句柄的消息类型,放在消息的arg2中,表示服务端正常
public static int SERVER_MSG_ERROR=1;//表示服务端出错
public static int SERVER_MSG_DIR=2;//表示DIR操作返回
public static int SERVER_MSG_OPN=3;//表示OPN操作返回
private int msgType;
private String ip;
private int port;
private int connect_timeout=10000;
private Handler handler;
private Socket socket;
public static final String KEY_SERVER_ACK_MSG = “KEY_SERVER_ACK_MSG”;
private OutputStreamWriter writer;
private BufferedReader bufferedReader;
public SocketClient(String ip, int port, Handler handler) {
this.port = port;
this.ip = ip;
this.handler = handler;
}

private void connect() throws IOException {//连接服务端函数
InetSocketAddress address = new InetSocketAddress(ip, port);
socket = new Socket();
socket.connect(address, connect_timeout);
}
private void writeCmd(String cmd) throws IOException {
BufferedOutputStream os=new BufferedOutputStream(socket.getOutputStream());
writer=new OutputStreamWriter(os,“UTF-8”);
writer.write(“1\n”);
writer.write(cmd+“\n”);
writer.flush();
}
private ArrayList readSocketMsg() throws IOException {
ArrayList msgList=new ArrayList<>();
InputStreamReader isr=new InputStreamReader(socket.getInputStream(),“UTF-8”);
bufferedReader=new BufferedReader(isr);
String numStr = bufferedReader.readLine();
int linNum = Integer.parseInt(numStr);
msgType=SERVER_MSG_ERROR;
if(linNum<1){
msgList.add(“服务端返回为空”);
return msgList;
}
String status = bufferedReader.readLine();
if(status.equalsIgnoreCase(“OK”)){
msgType=SERVER_MSG_OK;
}else if(status.equalsIgnoreCase(“DIR”)){
msgType=SERVER_MSG_DIR;
}else if(status.equalsIgnoreCase(“OPN”)){
msgType=SERVER_MSG_OPN;
}else{
msgList.add(status);//将服务端的错误信息放入消息列表
}
for (int i = 1; i <linNum ; i++) {
String s = bufferedReader.readLine();
msgList.add(s);
}
return msgList;
}
private void close() throws IOException {
bufferedReader.close();
writer.close();
socket.close();
}
private void doCmdTask(String cmd){
ArrayList msgList=new ArrayList<>();
try {
connect();
writeCmd(cmd);
msgList = readSocketMsg();
close();
} catch (IOException e) {
msgType=SERVER_MSG_ERROR;
msgList.add(e.toString());
e.printStackTrace();
}
Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putStringArrayList(KEY_SERVER_ACK_MSG,msgList);
message.arg2=msgType;
message.setData(bundle);
handler.sendMessage(message);

}
public void work(final String cmd){
new Thread(new Runnable() {
@Override
public void run() {
doCmdTask(cmd);
}
}).start();
}
}

Activity_main.xml添加一个textview来显示操作信息

<?xml version="1.0" encoding="utf-8"?>



MainActivity.java更改如下,添加handler对不同返回type的判定与不同操作,并且将操作结果显示在一个Textview中

package com.example.android_app;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import androidx.annotation.NonNull;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

public static final String KEY_SERVER_ACK_MSG = “KEY_SERVER_ACK_MSG”;
private Handler handler = null;
EditText url,way,dir;
ListView lv;
Button submit;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。

还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

Android 基础知识点

Java 基础知识点

Android 源码相关分析

常见的一些原理性问题

希望大家在今年一切顺利,进到自己想进的公司,共勉!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节。

还有 高级架构技术进阶脑图 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

Android 基础知识点

Java 基础知识点

Android 源码相关分析

常见的一些原理性问题

[外链图片转存中…(img-eq0WL2h6-1712400962557)]

希望大家在今年一切顺利,进到自己想进的公司,共勉!

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 13
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值