最近在做一个机器人的项目,需要用到TCP通讯这个东西。需要在手机做一个客户端,然后上去网上查了巨久巨多代码,为了避免让有需要的人少走弯路,就做一篇博文来推一下自己的做法,如果各位大大们有什么好的建议,也希望各位可以在评论区写下高见抑或是邮箱到1262706641@qq.com。
由于个人的时间问题,目前这个工程的mian文件加已经上传到github上进行管理,各位大佬可以自取。
传送门:https://github.com/KinFaiLeong/Android-TCP

首先是布局文件的代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true">
        <EditText
            android:id="@+id/ip"
            android:layout_width="280dp"
            android:layout_height="50dp"
            android:background="#7CB342"
            android:hint="IP:"
            android:textColor="#ffffff"
        />
        <EditText
            android:id="@+id/port"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:hint="端口:"
            android:background="#C0CA33"
            android:layout_toRightOf="@id/ip"
            android:inputType="number"
            />
        <Button
            android:id="@+id/connect"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/port"
            android:text="连接服务器"/>

    </RelativeLayout>

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        <TextView
            android:id="@+id/receive"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:background="#00ACC1"
            android:textColor="#FFFFFF"
            android:hint="接收区"
            android:textSize="18sp"
            android:gravity="center_horizontal"
            />
        <EditText
            android:id="@+id/send"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:background="#3949AB"
            android:hint="发送:"
            android:textColor="#ffffff"
            android:layout_below="@id/receive"/>
        <Button
            android:id="@+id/btn_1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="发送"
            android:layout_below="@+id/send"
            />
    </RelativeLayout>
</RelativeLayout>

为了更方便以后的维护和迭代,我将发送模块、连接接收模块放在了不同的线程之中。
接下来先来看看最简单的 发送线程 代码。

//线程名:Send
    public class Send extends Thread {
    private String send;
    private OutputStream outputStream;
    private  InputStream inputStream;
    private String ip;
    private int port;


    public Send(String msg,int port,String ip) {
        this.send = msg;
        this.ip = ip;
        this.port = port;
    }

    @Override
    public void run() {
        try {
            Socket socket = new Socket(ip,port);
            send="客户端发来:"+send;
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
            outputStream.write((send+"\n").getBytes("utf-8"));
            outputStream.flush();
            Log.v("AndroidChat","发送成功:"+send);
        }
        catch (Exception e){
            Log.v("AndroidChat","发送失败:"+send+"error"+e.getMessage());
            e.printStackTrace();
        }
    }
Socket,套接字。利用这个建立和服务器之间的连接,会用就行,想深入了解去看其他大大的详解,这里不做赘述。

(这里插入一些题外话,无论代码有多长,建议各位都应当逐个函数的输入,复制粘贴只会走更多弯路。)

接下来是发送接收线程的代码:

package com.example.tcptext;


import android.util.Log;

import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStream;
import java.net.Socket;

//线程名:ConnectThread
public class ConnectThread extends Thread {
    //Socket msg = null;//定义socket
    private OutputStream out_ip=null;//定义输出流(ip)
    OutputStream outputStream=null;
    private InputStream inputStream;
    private StringBuffer stringBuffer;
    private String ip;
    private int port;
    private Receive receive;
    private String string;
    private boolean isRun = true;
    private  MainActivity.Receive re;

    public ConnectThread(String ip, int port, MainActivity.Receive re) {
        this.ip = ip;
        this.port = port;
        this.re = re;
    }


    @Override
        public void run(){
        Socket so = null;
        try {
            so = new Socket(ip, port);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ": Hello");
            try {
                inputStream = so.getInputStream();
                out_ip = so.getOutputStream();
                Log.v("AndroidChat","开始连接服务器:"+ip+"/"+port);
                sleep(1000);
            }
               catch (IOException | InterruptedException e) {
                Log.v("AndroidChat","连接服务器失败"+e.getMessage());
                e.printStackTrace();
                return;
            }
            Log.v("AndroidChat","成功连接上服务器");
            /*
            下面是接收模块,你可以尝试探究如何将这个模块放在接收线程中。
            */

                try {
                    inputStream = so.getInputStream();
                    final byte[] buffer = new byte[1024];
                    final int len = inputStream.read(buffer);
                    System.out.println(new String(buffer,0,len));
                    Log.v("AndroidChat","接收成功:"+new String(buffer,0,len));
                    string = new String(buffer,0,len);
                    re.setString(string);
                    //上下两行会和MainActivity关联,是回调在显示屏的关键步骤。
                    MainActivity.callback();
                    System.out.println(new String(buffer,0,len));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    }

最后是核心模块(MainActivity)

package com.example.tcptext;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;


public class MainActivity extends AppCompatActivity {
     private Button mBtn_send;
     private Button mBtn_connect;
     private EditText mEt_send;
     private static TextView mTv_recv;
     private String ip;
     private int port;
     private String msg;
     private ConnectThread ct;
     private Send send;
     private Handler handler;
     static Receive re = new Receive();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mTv_recv = findViewById(R.id.receive);
        mBtn_connect = findViewById(R.id.connect);
        mBtn_send = findViewById(R.id.btn_1);


        final EditText mEt_ip = this.findViewById(R.id.ip);
        final EditText mEt_port = this.findViewById(R.id.port);
        final EditText mEt_send = this.findViewById(R.id.send);

/*
设置一个点击事件用以连接线程
*/
        mBtn_connect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ip = mEt_ip.getText().toString();//获取输入的ip
                port = Integer.parseInt(mEt_port.getText().toString());//获取输入的端口号
                ct = new ConnectThread(ip, port, re);//创建一个线程来处理消息的收发
                ct.start();
            }
        });
/*
设计一个点击事件用以发送消息
*/
        mBtn_send.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                msg = mEt_send.getText().toString();
                send = new Send(msg, port, ip);
                send.start();

            }
        }); 
    }
/*
这里是和连接接收线程中的 re.setString(string) 联动的,自己理解一下怎么走在脑子里面走一次就差不多了。
*/
static class Receive{
        private  String string;
        public String getString(){
            return string;
        }
        public void setString(String s){
            this.string = s;
        }
}
/*
下面的callback和连接接收线程中的 MainActivity.callback() 关联,线程运行到那一步后结束回到MainActivity中。
*/
public static void callback(){
        System.out.println("连接线程执行结束");
        mTv_recv.setText(re.getString());//这里是将接收到的文字显示在接收框内。
}
}
注意:
	1.这里的点击按钮必须要输入好IP和端口号否则会闪退,我也不知道是什么原因,有哪位大大知道的,麻烦说一下。
	2.每次连接接收完信息后都要点击一次连接服务器或者发送一条消息。各位可以一起探讨一下如何重新开启线程,反正我又百年不用Java,这个问题就留给各位了,哈哈哈。

最后,我分享一下我做这个程序的具体思路。零基础的朋友可以参照一下思路来遨游博海:
1.找到两个标准的TCP应用。这很关键,你必须得有标准的应用来测试才知道这是好的还是坏的。
2.善于利用 System.out.println(“哔哩吧啦”); 这个东西能很好的帮助你检查代码运行到什么地方。
3.将整个应用开发分成三个模块:连接服务器模块,发送信息模块,接收信息模块。每个模块还能再细分步骤:1.固定信息的传递(如连接模块就是固定IP和端口号);2.随机信息的传递。
4.优化你的界面,优化代码,做成自己理想的样子。

2.之后我会创一个Github账号将源码放出来,以便和大家一起学习交流。

3.这里用到的两个标准软件:PC端:TCPCOM android端:TCP连接

最后希望大家一起加油!用心攻破每个难题!

androidstudio tcp androidstudio tcp客户端_android