• Android14_IPC方式之Socket


    Socket也叫做“套接字”;是网络通信中的概念;

    分为流式套接字和用户数据报套接字两种,分别对应于网络的传输控制层的TCP和UDP协议;

    TCP协议是面向连接的协议,提供稳定的双向通信功能;本身具有超时重传功能,非常稳定;

    UDP是无连接的,提供不稳定的单向通信功能,UDP也是可以实现双向通信功能;UDP具有更好的效率,缺点是不保证数据一定能够正确传输;

    使用Socket来通信,有两点需要注意,首先需要声明权限:

    注意不能在主线程中访问网络,这会导致我们的程序无法在Android4.0及以上的设备中运行,会抛出异常;

    网络操作可能比较耗时,如果在主线程中运行会影响程序的响应效率。

    1、先看一下Manifest的设置:

    这里为了演示方便,还是使用一个应用,多进程模式。Service单独作为一个进程;

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.learnsocket">
        <uses-permission android:name="android.permission.INTERNET"/>
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <service
                android:name=".TCPService"
                android:enabled="true"
                android:exported="true"
                android:process=":TCPService"></service>
    
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

    2、客户端的代码:

    package com.example.learnsocket;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.annotation.SuppressLint;
    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.Message;
    import android.os.SystemClock;
    import android.text.TextUtils;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.TextView;
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.Socket;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class MainActivity extends AppCompatActivity implements View.OnClickListener {
        private static final String TAG = "Client";
        private static final int MESSAGE_RECEIVE_NEW_MSG = 1;
        private static final int MESSAGE_SOCKET_CONNECTED = 2;
    
        private Button mSendButton;
        private TextView mMessageTextView;
        private EditText mMessageEditText;
    
        private PrintWriter mPrintWriter;
        private Socket mClientSocket;
    
        @SuppressLint("HandlerLeak")
        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg){
                switch(msg.what){
                    case MESSAGE_RECEIVE_NEW_MSG:{   //新消息
                        mMessageTextView.setText(mMessageTextView.getText()+(String)msg.obj);
                        break;
                    }
                    case MESSAGE_SOCKET_CONNECTED:{  //连接成功
                        mSendButton.setEnabled(true);
                        break;
                    }
                    default:
                        break;
                }
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mMessageEditText = (EditText)findViewById(R.id.input);
            mMessageTextView = (TextView)findViewById(R.id.msgwindow);
            mSendButton = (Button)findViewById(R.id.sendbutton);
            mSendButton.setOnClickListener(this);
    
            Intent connectintent = new Intent(this,TCPService.class);
            startService(connectintent);
            new Thread(){
                @Override
                public void run(){
                    connectTCPServer();
                }
            }.start();
        }
    
        private void connectTCPServer(){
            Socket socket = null;
            while(socket == null){
                try{
                    socket = new Socket("localhost",8688);
                    mClientSocket = socket;
                    mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);
                    mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
                    Log.d(TAG,"connected server success");
                }catch(IOException e){
                    SystemClock.sleep(1000);
                    Log.d(TAG,"connect tcp server failed,retry...");
                }
            }
    
            try{
                BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while(!MainActivity.this.isFinishing()){
                    String msg = br.readLine();
                    Log.d(TAG,"receive :"+msg);
                    if(msg != null){
                        String time = formatDateTime(System.currentTimeMillis());
                        final String showedMsg = "server "+time+":"+msg+"
    ";
                        mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG,showedMsg).sendToTarget();
                    }
                }
                Log.d(TAG,"quit...");
                mPrintWriter.close();
                br.close();
                socket.close();
            }catch(IOException e){
                e.printStackTrace();
            }
    
    
        }
    
        @Override
        protected void onDestroy(){
            if(mClientSocket != null){
                try{
                    mClientSocket.shutdownInput();
                    mClientSocket.close();
                }catch(IOException e){
                    e.printStackTrace();
                }
            }
            super.onDestroy();
        }
    
        @Override
        public void onClick(View v){
            if(v == mSendButton){
                final String msg = mMessageEditText.getText().toString();
                if(!TextUtils.isEmpty(msg) && mPrintWriter !=null){
                    new Thread(){
                        @Override
                        public void run(){
                            mPrintWriter.println(msg);
                        }
                    }.start();
                    mMessageEditText.setText("");
                    String time = formatDateTime(System.currentTimeMillis());
                    final String showedMsg = "self "+ time + ":" + msg + "
    ";
                    mMessageTextView.setText(mMessageTextView.getText()+showedMsg);
                }
            }
        }
    
        @SuppressLint("SimpleDateFormat")
        private String formatDateTime(long time){
            return new SimpleDateFormat("(HH:mm:ss)").format(new Date(time));
        }
    }

    3、服务端的代码:

    package com.example.learnsocket;
    
    import android.annotation.SuppressLint;
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;
    
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Random;
    
    
    public class TCPService extends Service {
        private static final String TAG = "TCPService";
        private boolean mIsServiceDestroyed = false;
        private String[] mDefinedMessages = new String[] {
                "你好啊,哈哈",
                "请问你叫什么名字呀?",
                "今天北京天气不错啊,shy",
                "你知道吗?我可是可以和多个人同时聊天的哦",
                "给你讲个笑话吧:据说爱笑的人运气不会太差,不知道真假。"
        };
    
        @Override
        public void onCreate(){
            new Thread(new TcpServer()).start();
            super.onCreate();
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
    
        @Override
        public void onDestroy(){
            mIsServiceDestroyed = true;
            super.onDestroy();
        }
    
    
        public TCPService() {
        }
    
    
        private class TcpServer implements Runnable{
            @SuppressLint("resource")
            @Override
            public void run(){
                ServerSocket serverSocket = null;
                try{
                    //监听本地8688端口
                    serverSocket =new ServerSocket(8688);
                }catch(IOException e){
                    Log.d(TAG,"establish tcp server failed, port:8688");
                    e.printStackTrace();
                    return;
                }
    
                while(!mIsServiceDestroyed){
                    try{
                        //接收客户端请求
                        final Socket client = serverSocket.accept();
                        Log.d(TAG,"accept");
                        new Thread() {
                            @Override
                            public void run() {
                                try {
                                    responseClient(client);
                                }catch(IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }.start();
                    }catch(IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    
        private void responseClient(Socket client)throws IOException {
            //用于接收客户端消息
            BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
            //用于向客户端发送消息
            PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())),true);
            out.println("欢迎来到聊天室");
            while(!mIsServiceDestroyed){
                String str = in.readLine();
                Log.d(TAG,"msg from client: "+str);
                if(str == null){
                    break;
                }
                int i = new Random().nextInt(mDefinedMessages.length);
                String msg = mDefinedMessages[i];
                out.println(msg);
                Log.d(TAG,"send :"+msg);
            }
            Log.d(TAG,"client quit.");
            in.close();
            out.close();
            client.close();
    
        }
    }

    4、activity的布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.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=".MainActivity">
    
        <Button
            android:id="@+id/sendbutton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Send"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.89"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/msgwindow" />
    
        <TextView
            android:id="@+id/msgwindow"
            android:layout_width="match_parent"
            android:layout_height="592dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.13999999" />
    
        <EditText
            android:id="@+id/input"
            android:layout_width="260dp"
            android:layout_height="51dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/sendbutton"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/msgwindow" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
  • 相关阅读:
    python+webdriver(二)
    python+webdriver(一)
    重逢
    在C,C++,java和python运行时解释器和编译器的区别
    hive调优
    github 操作指南
    jupyter 启动时的问题
    海量数据模型实施方法论
    python之Tkinker学习
    使用cmd命令行进行本地证书读取
  • 原文地址:https://www.cnblogs.com/grooovvve/p/12489739.html
Copyright © 2020-2023  润新知