欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android——socket连接(客户端发消息给服务端)

程序员文章站 2022-05-21 13:44:06
...

准备工作

一台手机作服务端,一台手机作客户端,两部手机连接同一个wifi

服务端

布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.jie.socketdemo.MainActivity">

    <TextView
        android:id="@+id/info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        app:layout_constraintTop_toBottomOf="@+id/info"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>

MainActivity

public class MainActivity extends AppCompatActivity {

    private TextView mTvInfo;
    private TextView mTvGetData;
    private ServerSocket mServerSocket = null;
    private InputStream mInputSteam;
    private String ip;
    private int port;

    StringBuffer mStringBuffer = new StringBuffer();

    public Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    //本地ip和port信息
                    mTvInfo.setText(msg.obj.toString());
                    break;
                case 2:
                    //从客户端获取到的消息
                    mTvGetData.setText("CustomInfo:"+msg.obj.toString());
                    mStringBuffer.setLength(0);
                    break;

            }

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTvInfo = findViewById(R.id.info);
        mTvGetData = findViewById(R.id.data);

        receiveData();
    }

    /**
     * 服务器端接收数据
     * 需要注意以下一点:
     * 服务器端应该是多线程的,因为一个服务器可能会有多个客户端连接在服务器上;
    */
    public void receiveData() {
        Thread thread = new Thread() {
            @Override
            public void run() {
                super.run();
                /*指明服务器端的端口号*/
                try {
                    mServerSocket = new ServerSocket(8000);
                } catch (IOException e) {
                    e.printStackTrace();
                }

                getLocalIpAddress(mServerSocket);

                Message msg = handler.obtainMessage();
                msg.what = 1;
                msg.obj = "IP:" + ip + " , PORT: " + port;
                handler.sendMessage(msg);

                //持续获取消息
                while (true) {
                    Socket socket = null;
                    try {
                        if (mServerSocket != null) {
                            socket = mServerSocket.accept();
                            mInputSteam = socket.getInputStream();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    new ServerThread(socket, mInputSteam).start();
                }
            }
        };
        thread.start();
    }

    private void getLocalIpAddress(ServerSocket serverSocket) {
        try {
            //for(;;)
            for (Enumeration<NetworkInterface> mEnumNetwork = NetworkInterface.getNetworkInterfaces(); mEnumNetwork.hasMoreElements();) {
                NetworkInterface mNetwork = mEnumNetwork.nextElement();
                for (Enumeration<InetAddress> mEnumIpAddress = mNetwork.getInetAddresses(); mEnumIpAddress.hasMoreElements();) {
                    InetAddress mIpAddress = mEnumIpAddress.nextElement();
                    String mIp = mIpAddress.getHostAddress().substring(0, 3);
                    if(mIp.equals("192")){
                        ip = mIpAddress.getHostAddress();    //获取本地IP
                        port = serverSocket.getLocalPort();    //获取本地的PORT
                    }
                }
            }
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    class ServerThread extends Thread {
        private Socket socket;
        private InputStream inputStream;
        private StringBuffer stringBuffer = mStringBuffer;

        public ServerThread(Socket socket, InputStream inputStream) {
            this.socket = socket;
            this.inputStream = inputStream;
        }

        @Override
        public void run() {
            int len;
            byte[] bytes = new byte[24];
            boolean isString = false;

            try {
                if (inputStream != null) {
                    //输入流关闭时循环才会停止
                    //数据读完了,再读是等于0
                    while ((len = inputStream.read(bytes)) != -1) {
                        for (int i = 0; i < len; i++) {
                            if (bytes[i] != '\0') {
                                stringBuffer.append((char) bytes[i]);
                            } else {
                                isString = true;
                                break;
                            }
                        }
                        if (isString) {
                            Message msg = handler.obtainMessage();
                            msg.what = 2;
                            msg.obj = stringBuffer;
                            handler.sendMessage(msg);
                            isString = false;
                        }
                    }
                }
            } catch (IOException e) {
                //当这个异常发生时,说明客户端那边的连接已经断开
                e.printStackTrace();
                try {
                    inputStream.close();
                    socket.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }

            }
        }
    }

    /*当按返回键时,关闭相应的socket资源*/
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        try {
            mServerSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

客户端

布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.jie.socketcustomdemo.MainActivity">

    <EditText
        android:id="@+id/et_ip"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="40dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="connect"
        android:onClick="connect"
        app:layout_constraintTop_toTopOf="@id/et_ip"
        app:layout_constraintLeft_toRightOf="@+id/et_ip" />

    <EditText
        android:id="@+id/et_data"
        android:layout_width="200dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_marginLeft="40dp"
        app:layout_constraintTop_toBottomOf="@id/et_ip"
        app:layout_constraintLeft_toLeftOf="parent" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="send"
        android:onClick="send"
        app:layout_constraintTop_toTopOf="@id/et_data"
        app:layout_constraintLeft_toRightOf="@+id/et_data" />

</android.support.constraint.ConstraintLayout>

MainActivity

public class MainActivity extends AppCompatActivity {

    private EditText mEtIp,mEtData;
    private OutputStream mOutputStream = null;
    private Socket mSocket = null;
    private String ip;
    private String data;
    private boolean socketStatus = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mEtIp = findViewById(R.id.et_ip);
        mEtData = findViewById(R.id.et_data);
    }

    public void connect(View view){
        ip = mEtIp.getText().toString();
        Toast.makeText(MainActivity.this,""+ip,Toast.LENGTH_SHORT).show();

        Thread thread = new Thread(){
            @Override
            public void run() {
                super.run();
                if (!socketStatus) {
                    try {
                        //连接服务端
                        mSocket = new Socket(ip,8000);
                        if(mSocket != null){
                            socketStatus = true;
                        }

                        mOutputStream = mSocket.getOutputStream();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();
    }

    public void send(View view){
        data = mEtData.getText().toString();
        Toast.makeText(MainActivity.this,""+data,Toast.LENGTH_SHORT).show();

        if (data != null) {
            //在后面加上 '\0' ,是为了在服务端方便我们去解析;
            data = data + '\0';
        }

        Thread thread = new Thread(){
            @Override
            public void run() {
                super.run();
                if(socketStatus){
                    try {
                        mOutputStream.write(data.getBytes());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        thread.start();
    }

    /*当客户端界面返回时,关闭相应的socket资源*/
    @Override
    public void onBackPressed() {
        super.onBackPressed();
        /*关闭相应的资源*/
        try {
            mOutputStream.close();
            mSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

注意

服务端和客户端都要添加权限

<!--允许应用程序改变网络状态-->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--允许应用程序改变WIFI连接状态-->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<!--允许应用程序访问有关的网络信息-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--允许应用程序访问WIFI网卡的网络信息-->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--允许应用程序完全使用网络-->
<uses-permission android:name="android.permission.INTERNET"/>

效果

客户端
Android——socket连接(客户端发消息给服务端)
服务端
Android——socket连接(客户端发消息给服务端)