Android socket 编程例子

最近和几个同学在做一个使用Android端client控制单片机的项目。整个项目的构建思路是:手机APP使用socket TCP与PC端连接,PC则使用串口通信与单片机连接,最终实现用手机控制单片机的功能。在这篇博客里,我主要是说说关于Android端APP使用socket TCP与PC相连接并接收和发送消息的部分。

Java部分的结构

java代码结构


三个子线程类
SocketConnectorThread 启动Socket TCP链接的子线程
ReceiveMsgThread 接收消息线程
SendMsgThread 发送消息线程


两个activity类
MainActivity 登陆到服务器(PC服务器)的界面
CommandActivity 消息发送和接收界面


一个Manager类
Manager 用于转发消息给各个类以及socket对象的引用

接下来,一个一个地说明

MainActivity

public class MainActivity extends AppCompatActivity {
    private EditText port_text;
    private EditText ip_text;
    private Button link_to_server;
    private int PORT;
    private String IP;
    //Socket连接线程
    private SocketConnectorThread connectorThread;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();  //初始化主界面的方法
        initClick();
    }
    //初始化界面
    protected void initView(){
        port_text = (EditText) findViewById(R.id.port_text);
        ip_text = (EditText) findViewById(R.id.ip_text);
        link_to_server = (Button) findViewById(R.id.link_btn);
    }
    //初始化按钮监听事件
    protected void initClick(){
        //链接到服务器
        link_to_server.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (port_text.getText().toString().trim().length() != 0 && ip_text.getText().toString().trim().length() != 0){
                    connect();
                    jumpToController();
                }else{
                    Toast.makeText(MainActivity.this, "请输入PORT或IP",Toast.LENGTH_SHORT).show();
                }
            }
        });
    }
    //初始化链接并创建Client
    protected void connect(){
        IP = ip_text.getText().toString();  //从EditText中获得IP为String类型
        PORT = Integer.parseInt(port_text.getText().toString());  //从EditText中获得PORT转换为int类型
        connectorThread = new SocketConnectorThread(IP, PORT);
        connectorThread.start();  //开启链接服务器的线程
    }

    //跳转到控制窗口
    protected void jumpToController(){
        Intent intent = new Intent(MainActivity.this, CommandActivity.class);
        startActivity(intent);
        this.finish();
    }
}

CommandActivity

public class CommandActivity extends AppCompatActivity implements View.OnClickListener{

    private Manager manager = Manager.getManager();
    //9个指令按钮
    private Button code_btn_1;
    private Button code_btn_2;
    private Button code_btn_3;
    private Button code_btn_4;
    private Button code_btn_5;
    private Button code_btn_6;
    private Button code_btn_7;
    private Button code_btn_8;
    private Button code_btn_9;
    //一个指令显示的text
    private TextView show_command;
    //ScrollView
    private ScrollView sc;
    //发送消息的线程
    private SendMsgThread sendMsgThread;
    //接收消息的线程
    private ReceiveMsgThread receiveMsgThread;
    // 定义Handler对象
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            // 处理UI
            switch (msg.what){
                case Single.RECEIVE_MSG:
                    //更新收到的消息显示
                    setShow_received();
                    break;
                case Single.SEND_MSG:
                    //更新指令显示
                    setShow_command();
                    break;
                case Single.SYSTEM_MSG:
                    //更新系统提示显示
                    setShow_systemMsg();
                    break;
                default:
                    break;
            }
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_command_acitivity);
        initView();    //初始化界面
        setClick();    //按钮监听
        startThreads();    //开启接收和发送消息的两个线程
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.settings_menu,menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()){
            case R.id.item_about:
                show_about();
                break;
            case R.id.item_exit:
                exit_app();
                break;
        }
        return true;
    }
    //结束程序
    protected void exit_app(){
        try {
            manager.getSocket().close();
        } catch (IOException e) {
            System.exit(0);
        }
        System.exit(0);
    }
    //显示关于对话框
    protected void show_about(){
        new AlertDialog.Builder(this)
        .setTitle("关于")
                .setMessage("Controller Beta 1.0")
                .setPositiveButton("确定",null)
                .show();
    }


    //初始化界面
    protected void initView(){
        //指令按钮
        code_btn_1 = (Button) findViewById(R.id.code1);
        code_btn_2 = (Button) findViewById(R.id.code2);
        code_btn_3 = (Button) findViewById(R.id.code3);

        code_btn_4 = (Button) findViewById(R.id.code4);
        code_btn_5 = (Button) findViewById(R.id.code5);
        code_btn_6 = (Button) findViewById(R.id.code6);

        code_btn_7 = (Button) findViewById(R.id.code7);
        code_btn_8 = (Button) findViewById(R.id.code8);
        code_btn_9 = (Button) findViewById(R.id.code9);
        //指令显示
        show_command = (TextView) findViewById(R.id.showCommand);
    }

    //按钮添加监听
    protected void setClick(){
        code_btn_1.setOnClickListener(this);
        code_btn_2.setOnClickListener(this);
        code_btn_3.setOnClickListener(this);

        code_btn_4.setOnClickListener(this);
        code_btn_5.setOnClickListener(this);
        code_btn_6.setOnClickListener(this);

        code_btn_7.setOnClickListener(this);
        code_btn_8.setOnClickListener(this);
        code_btn_9.setOnClickListener(this);
    }

    //指令按钮的监听分类
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.code1:
                sendCommand(Single.GET_TEMPERATURE);  //获取温度
                break;
            case R.id.code2:
                sendCommand(Single.BUZZER);  //LED开关
                break;
            case R.id.code3:
                sendCommand(Single.FAN);  //风扇开关
                break;
            case R.id.code4:
                sendCommand(Single.LED);  //蜂鸣器开关
                break;
//            case R.id.code5:
//                sendCommand("4");
//                break;
//            case R.id.code6:
//                sendCommand("12");
//                break;
//            case R.id.code7:
//                sendCommand("20");
//                break;
//            case R.id.code8:
//                sendCommand("21");
//                break;
//            case R.id.code9:
//                sendCommand("22");
//                break;
            default:
                break;
        }
    }

    //发送指令
    protected void sendCommand(int command){
        sendMsgThread.sendMessage(Integer.toString(command));
    }

    //显示发送的指令
    protected void setShow_command(){
        show_command.setText(show_command.getText().toString()+"\n发送指令:"+manager.getSend_msg());
    }

    //显示接收的消息
    protected void setShow_received(){
        show_command.setText(show_command.getText().toString()+"\n服务器回复:"+manager.getReceive_msg());
    }

    //显示系统提示
    protected void setShow_systemMsg(){
        show_command.setText(show_command.getText().toString()+"\n系统提示:"+manager.getSystem_msg());
    }

    //开启接收和发送消息的两个线程
    protected void startThreads(){
        sendMsgThread = new SendMsgThread(manager.getSocket(), mHandler, manager);
        receiveMsgThread = new ReceiveMsgThread(manager.getSocket(), mHandler, manager);
        receiveMsgThread.start();
        sendMsgThread.start();
    }
}

接下来是三个线程

SocketConnectorThread

public class SocketConnectorThread extends Thread{
    private Manager manager = Manager.getManager();
    private int PORT;
    private String IP;
    private final Socket socket = new Socket();

    //构造方法(ip, port)
    public SocketConnectorThread(String ip, int port){
        this.IP = ip;
        this.PORT = port;
    }

    @Override
    public void run() {
        try {
            this.socket.connect(new InetSocketAddress(IP,PORT));
            manager.setSocket(this.socket);  //当Socket连接成功后将对象传给manager的引用
        } catch (IOException e) {

        }
    }
}

ReceiveMsgThread

public class ReceiveMsgThread extends Thread{
    private DataInputStream in = null;
    private Manager manager;
    private Socket socket;
    private Handler handler;
    //构造方法(Socket)
    public ReceiveMsgThread(Socket s, Handler h, Manager m){
        this.socket = s;
        this.handler = h;
        this.manager = m;
    }

    @Override
    public void run() {
        while (true){
            try {
                in = new DataInputStream(this.socket.getInputStream());
                byte[] bytes = new byte[in.available()];
                if (bytes.length != 0){
                    in.read(bytes);
                    String str = new String(bytes,"UTF-8");
                    manager.setReceive_msg(str);
                    handler.sendEmptyMessage(Single.RECEIVE_MSG);
                }
            } catch (IOException e) {
                manager.setSystem_msg("消息接收失败");
                handler.sendEmptyMessage(Single.SYSTEM_MSG);
            }
        }
    }
}

SendMsgThread

public class SendMsgThread extends Thread {
    private Manager manager;
    private Socket socket;
    private Handler handler;
    private DataOutputStream out = null;
    private String message;    //用于暂存用户需要发向服务器的消息
    public int flag = 0;

    //构造方法(Socket, Handler)
    public SendMsgThread(Socket s, Handler h, Manager m){
        this.socket = s;
        this.handler = h;
        this.manager = m;
    }

    //用于接受用户需要发向服务器的消息
    public void sendMessage(String message){
        this.message = message;
        flag = 1;
    }

    @Override
    public void run() {
        while (true){
            if (flag == 1){
                sendMsg(this.message);
                manager.setSend_msg(this.message);
                handler.sendEmptyMessage(Single.SEND_MSG);
                flag = 0;
            }
        }
    }
    //发送消息的方法
    protected void sendMsg(String message){
        try {
            out = new DataOutputStream(this.socket.getOutputStream());
            byte[] by = (message+"\n").getBytes();
            out.write(by);
            out.flush();
            if (!socket.isConnected()){
                manager.setSystem_msg("与服务器连接已断开,消息发送失败");
                handler.sendEmptyMessage(Single.SYSTEM_MSG);
            }
            flag = 0;
        } catch (IOException e) {
            manager.setSystem_msg("消息发送失败");
            handler.sendEmptyMessage(Single.SYSTEM_MSG);
        }
    }
}

layout部分

布局文件
对于这个布局来说,具体什么样子可以自己定义

activity_main

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        tools:ignore="UselessParent">
        <EditText
            android:id="@+id/port_text"
            android:layout_marginTop="20dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/port_num"
            android:hint="@string/port"/>
        <EditText
            android:id="@+id/ip_text"
            android:layout_marginTop="20dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/ip_num"
            android:hint="@string/ip"/>
        <Button
            android:id="@+id/link_btn"
            android:layout_marginTop="20dp"
            android:layout_gravity="center_horizontal"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/login"/>
    </LinearLayout>
</LinearLayout>
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页