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

准备工作

一台手机作服务端,一台手机作客户端,两部手机连接同一个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"/>

效果

客户端
这里写图片描述
服务端
这里写图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42164949/article/details/81512610