This article reprints the article, read the original source code can be obtained, at the end of the article has the original link

PS: This article is about using Socket for inter-process communication, the demo is written in Kotlin language

1. Use Socket

Socket is the middle software abstraction layer for communication between application layer and TCP/IP protocol family. It is shown as a programming interface (API) that encapsulates TCP/IP protocol family.

It can be divided into streaming socket and user datagram socket, which correspond to TCP and UDP protocols in the transmission control layer of the network respectively.

TCP protocol is a connection-oriented protocol, providing stable two-way communication function, the establishment of the connection needs to be completed through “three handshakes”, in order to provide stable data transmission function; TCP to ensure reliable packet transmission line, will give each package a serial number, the serial number at the same time also ensure that the host can be sent to the receiving end receives in order, and then the receiver host for a successful received packets sent back a corresponding confirmation character, if the sender host did not receive confirmation within reasonable round-trip delay characters, The corresponding packet is considered lost and will be retransmitted; UDP is a connectionless protocol, which does not guarantee reliability. UDP has the disadvantages of not providing packet grouping, assembly and not sorting packets, that is, it is impossible to know whether they arrive safely and completely. But in terms of performance, UDP has better efficiency.

When we use Socket for IPC communication, it also belongs to the network operation, which is very likely to be time-consuming. Therefore, when receiving or sending data, we should try to use the child thread to operate, because putting it in the main thread will affect the response efficiency of the program, and the network should not be accessed in the main thread in terms of performance. So let’s do a demo;

(1) On the server side, create a MyService of class KT (package name com.xe. ipcService) and inherit it:

class MyService: Service() {

private var mIsServiceDestoryed = false private val TAG = "MyService" override fun onBind(intent: Intent?) : IBinder { return null!! } override fun onDestroy() { super.onDestroy() mIsServiceDestoryed = true } override fun onCreate() { super.onCreate() Thread(TcpServer()).start() } private fun recevi(client: Socket) { var inB: BufferedReader? = null var out: PrintWriter? = null try { inB = BufferedReader(InputStreamReader(client.getInputStream())) out = PrintWriter(BufferedWriter(OutputStreamWriter(client.getOutputStream())), true) var msg: String = "" while (! mIsServiceDestoryed) { Thread.sleep(50) msg = inB!! .readLine() if (msg ! = null) { var s: Println (s)} else {log. d(TAG, "MSG == null")}}} catch (e: IOException) { e.printStackTrace() } catch (e: InterruptedException) { e.printStackTrace() } finally { if (out ! = null) { out.close() } if (inB ! = null) { try { inB.close() } catch (e: IOException) { e.printStackTrace() } } } } internal inner class TcpServer : Runnable { override fun run() { var serverSocket: ServerSocket? = null try { serverSocket = ServerSocket(8083) } catch (e: IOException) { e.printStackTrace() } while (! mIsServiceDestoryed) { try { val client = serverSocket!! .accept() recevi(client) } catch (e: IOException) { e.printStackTrace() } } } }

We start with a child thread, create a ServerSocket object, and wait for the client to connect. When the client connects successfully, we start with the ServerSocket object and wait for the client to connect. ServerSocket object to get the input stream BufferedReader and output stream PrintWriter; The data received from the client via BufferedReader is embellished and then sent to the client via PrintWriter.

(2) Create an Activity of type KT with the name ClientActivity (package name com.xe. ipcDemo5) :

class ClientActivity : AppCompatActivity() {

var mBtnConnect: Button? = null var mTvMessage: TextView? = null var mBtnSend: Button? = null var mH: Handler? = null var mReceiveThread: Thread? = null var mPrintWriter: PrintWriter? = null var mClientSocket: Socket? = null var isThreadActive: Boolean = true var mdefinedMessages = arrayOf(" Hello!" , "What's your name, please? "," It's a nice day today ", "I'll tell you a joke "," This companion object can be used to chat with people ") Int = 1 var UPDATE_VIEW: Int = 2 var TAG: String = "ClientActivity" } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_client) init(); startMyService() } fun startMyService() { startService(Intent(this, MyService::class.java)) } fun init() { mBtnConnect = findViewById(R.id.btn_connect) mTvMessage = findViewById(R.id.tv_message) mBtnSend = findViewById(R.id.btn_send); mH = MyHandler(); mReceiveThread = ReceiveThread(); } fun onClick(v: View) { if (v.id == R.id.btn_connect) { connect(v) } else if (v.id == R.id.btn_send) { sendMessage(v) } } fun sendMessage(v: View) { mBtnSend!! .isEnabled = false var t: Thread = SendThread() t.start() } inner class SendThread : Thread() { override fun run() { super.run() try { var index: Int = Random().nextInt(mDefinedMessages.size) if (mPrintWriter ! = null) { mPrintWriter!! .println(mDefinedMessages[index]) } else { Log.d(TAG,"mPrintWriter == null") } } catch (e: Exception) { } finally { mH!! .sendEmptyMessage(UPDATE_VIEW) } } } fun connect(v: View) { mReceiveThread!! .start() v.isEnabled = false } inner class MyHandler : Handler() { override fun handleMessage(msg: Message?) { super.handleMessage(msg) if (msg!! .what == MESSAGE_SOCKET_CONNECTED) { var message: String = msg!! .obj as String var mTvContent: String = mTvMessage!! .text.toString() mTvContent = mTvContent + "\n" + message mTvMessage!! .setText(mTvContent) } else if (msg!! .what == UPDATE_VIEW){ mBtnSend!! .isEnabled = true } } } inner class ReceiveThread : Thread() { override fun run() { super.run() var socket: Socket? = null while (Socket == null) {try {Socket = Socket("127.0.0.1", 8083); mClientSocket = socket; mPrintWriter = PrintWriter(BufferedWriter(OutputStreamWriter(socket.getOutputStream())), true); } catch (e: IOException) { e.printStackTrace(); } } var br: BufferedReader? = null try { br = BufferedReader(InputStreamReader(socket.getInputStream())); while (isThreadActive) { var msg = br!! .readLine() Thread.sleep(500); if (msg ! = null) { var message: Message = Message.obtain(); message.what = MESSAGE_SOCKET_CONNECTED message.obj = msg mH!! .sendMessage(message); } } } catch (e: IOException) { e.printStackTrace(); } catch (e: InterruptedException) { e.printStackTrace(); } finally { if (br ! = null) { try { br.close(); } catch (e: IOException) { e.printStackTrace(); } } } try { socket.close(); } catch (e: IOException) { e.printStackTrace(); } } } override fun onDestroy() { super.onDestroy() isThreadActive = false; mReceiveThread = null if (mPrintWriter ! = null) { mPrintWriter!! .close() mPrintWriter = null } if (mClientSocket ! = null) { try { mClientSocket!! .shutdownInput() mClientSocket!! .close() } catch (e: IOException) { e.printStackTrace() } } }

}

The layout file for ClientActivity activity_client is as follows:

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" android:orientation="vertical" tools:context="com.xe.ipcdemo5.ClientActivity"> <Button android:id="@+id/btn_connect" Android :layout_width="match_parent" android:text=" connect to server "android:onClick="onClick" android:layout_height="wrap_content" /> <Button android:id="@+id/btn_send" android:layout_width="match_parent" android:text=" send a message" android:onClick="onClick" android:layout_height="wrap_content" /> <TextView android:id="@+id/tv_message" android:layout_width="match_parent" android:layout_height="wrap_content" />

< / LinearLayout > first, client first open MyService also opened up a process at the same time, by clicking on the “connect to the server” button to open a child thread ReceiveThread, the child thread main thing is to create a Socket object through the port number 8083, Obtain an input stream BufferedReader and an output stream PrintWriter through Socket object, and then wait for receiving data through BufferedReader. The received data is switched to the main thread and displayed with TextView. Click the “Send a Message” button, and the main thing you do is start a child thread to send the data using the PrintWriter.

(3) Configure the AndroidManifest.xml file accordingly:

package="com.xe.ipcdemo5">
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<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">
    <activity android:name=".ClientActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service android:name="com.xe.ipcservice.MyService"
        android:process=":remote">
    </service>
</application>

</manifest>

The interface to start the program is as follows:

The picture

Click the “Connect to the server” button and then click the “Send a message” button. The interface changes as follows:

The picture

The console log print looks like this:

The picture