Android IPC通信之Socket

  Unix系统中支持进程间通信(IPC),IPC的接口设计得类似文件IO操作接口。在Unix中,一个进程会有一套可以进行读取写入的IO描述符。IO描述符可以说是文件、设备或者是通信通道(socket套接字)。一个文件描述符由三部分组成:创建(打开socket)、读取写入数据(接收和发送到socket)、销毁(关闭socket)。
  消息的目的地址是使用socket地址来表示,一个socket地址是由网络地址和端口号组成的通信标识符。
  进程间通信操作需要客户端和服务器端分别有一个socket对象。当一个消息发出后,这个消息在发送端的socket中处于排队状态,直到下层的网络协议将这些消息发送出去;当消息到达接收端的socket后,也会处于排队状态,直到接收端的进程对这条消息进行了接收处理。
  对于socket编程可以有两种通信协议可以选择:数据报通信和流通信。数据报通信就是UDP,UDP是一种无连接的协议,这意味着我们每次发送数据报时,需要同时发送本机的socket描述符和接收端的描述符。流通信即TCP,TCP是一种基于连接的协议,在通信之前,必须在通信的一对儿socket之间建立连接,其中的一个socket作为服务器进行监听请求,另一个作为客户端进行连接请求,一旦两个socket建立好了连接,他们可以单向或者双向进行数据传输。
  TCP还是UDP的选择。
  UDP报头有64KB的限制,发送的数据不一定会被接收端按顺序接收;而TCP一旦socket建立了连接,它们之间的通信如同IO流,没有大小限制,接收端收到的包和发送端的顺序一致。因此TCP适合远程登录和文件传输这类的网络服务,因为这些需要传输的数据大小不确定。UDP相比TCP轻量一些,用于实现实时性较高或者丢包不重要的一些服务,例如微信消息的接收发送,在局域网内,UDP的丢包率相对较低。

一、基于UDP的Socket通信

客户端

客户端通过将数据放到byte数组中:

byte[] Data = “你想要发送的文本”.getBytes();

并通过一个数据包对象将数据封装:

DatagramPacket packetS  = new DatagramPacket(Data,Data.length,address,port);

最后通过DataGramSocket对象将该数据包发送:

client = new DatagramSocket();
client.send(packetS);

(1)设置网络连接权限
在manifest文件的application前添加网络访问权限:

<uses-permission android:name="android.permission.INTERNET" />

(2)客户端代码

package com.ipc.lijiao.udpcilent;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

public class MainActivity extends AppCompatActivity {

    EditText et;
    Button sd;
    int port = 8800;
    String host = "127.0.0.1";
    DatagramSocket client;
    Handler mhandler = new Handler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et = (EditText)findViewById(R.id.et);
        sd = (Button)findViewById(R.id.sd);

        sd.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                String content = et.getText().toString();

                Send send = new Send(content);
                send.start();
            }
        });
    }

    public  class  Send  extends Thread{
        String content;
        InetAddress address;
        private  Send(String content)
        {
            this.content = content;
        }
        public  void run()
        {
            try {
                 address = InetAddress.getByName(host);
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
            byte[] Data = content.getBytes();
            DatagramPacket packetS  = new DatagramPacket(Data,Data.length,address,port);
            try {
                client = new DatagramSocket();
            } catch (SocketException e) {
                e.printStackTrace();
            }
            try {
                client.send(packetS);
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] DataSend = new byte[300];
            /**
            DatagramPacket 需要新建对象,创建方式如果为packetS = new DatagramPacket(DataSend,DataSend.length);packetS仍然会指向原对象。
            **/
            DatagramPacket packetR = new DatagramPacket(DataSend,DataSend.length);

            try {
                client.receive(packetR);
            } catch (IOException e) {
                e.printStackTrace();
            }
            content = new String(packetR.getData(),0,packetR.getLength());
            mhandler.post(new Runnable() {
                @Override
                public void run() {
                    et.setText(content);
                }
            });
            client.close();
        }

    }

}

服务端

(2)服务器端
服务器端首先需要设置一个数据接收容器:

byte[] Data = new byte[300];

设置接收数据包:

DatagramPacket packetR = new DatagramPacket(Data,Data.length);

通过DataGramSocket对象接收数据到DatagramPacket对象中:

server = new DatagramSocket(8800);
server.receive(packetR);

读取数据:

content = new String(packetR.getData(),0,packetR.getLength());

(1)设置网络连接权限
在manifest文件的application前添加网络访问权限:

<uses-permission android:name="android.permission.INTERNET" />

(2)服务端代码

package com.ipc.lijiao.udpserver;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

public class MainActivity extends AppCompatActivity {

    int Max_SIZE = 300;
    TextView show;
    Handler mhandler;
    String content;
    DatagramSocket server;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        show = (TextView)findViewById(R.id.show);
        mhandler = new Handler();
        Server ImpServer = new Server();
        Thread server = new Thread(ImpServer);
        server.start();
    }

    public class  Server implements   Runnable{


        @Override
        public void run() {
            byte[] Data = new byte[Max_SIZE];
            DatagramPacket packetR = new DatagramPacket(Data,Data.length);
            try {
                 server = new DatagramSocket(8800);
            } catch (SocketException e) {
                e.printStackTrace();
            }
            while (true)
            {
                try {
                    server.receive(packetR);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                content = new String(packetR.getData(),0,packetR.getLength());
                mhandler.post(new Runnable() {
                    @Override
                    public void run() {
                        show.setText(content);
                    }
                });
                byte[] DataS = ("Servier:"+content).getBytes();
                DatagramPacket packetSend = new DatagramPacket(DataS,DataS.length,packetR.getAddress(),packetR.getPort());
                try {
                    server.send(packetSend);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    public void onDestroy(){
        super.onDestroy();
        server.close();
    }
}

二、基于TCP的Socket通信

客户端

(1)基本思路
客户端通过服务端的host和port创建一个Socket对象:

client = new Socket(host,port);

向服务端发送消息使用BufferedWriter对象:

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
client.getOutputStream()));
writer.write(show.getText().toString());
writer.flush();
client.shutdownOutput();

使用client.shutdownOutput()单向关闭写入流(如果不关闭写入流,则数据不会真正写到服务端),如果使用writer.close()会将socket对象一并关闭。

(2)demon

package com.ipc.lijiao.ipcclient;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    EditText show ;
    Button socketB ;
    Handler mhandler = new Handler();
    Socket client;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        show = (EditText)findViewById(R.id.show);
        socketB = (Button)findViewById(R.id.socketB);
        socketB.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch(v.getId())
        {
            case R.id.socketB:
            {
                new Thread()
                {
                    public void run()
                    {
                       // String host = "172.17.100.77";
                        String host = "127.0.0.1";
                        int port = 8919;
                        try
                        {
                                client = new Socket(host,port);
                                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
                                writer.write(show.getText().toString());
                                writer.flush();
                                client.shutdownOutput();

                                BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
                                String content = "";

                                while(true)
                                {
                                    String line = null;
                                    line = reader.readLine();
                                    if(line == null)
                                        break;
                                    content = content + line;
                                }
                                client.shutdownInput();

                                final String context = content;
                                mhandler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        show.setText(context);
                                    }
                                });
                            client.close();
                        }catch(IOException e)
                        {
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        }
    }

    public void onDestroy() {
        super.onDestroy();
        mhandler.removeCallbacksAndMessages(null);
        mhandler = null;
    }
}

服务端

(1)基本思路
服务端会创建ServerSocket对象,并通过该对象的accept()方法监听端口:

ServerSocket server = new ServerSocket(port);
Socket socket = server.accept();

socket对象通过BufferReader来接收信息,并通过ReadLine读取信息:

BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true)
{
    String line = null;
    line = reader.readLine();
    if(line == null)
        break;
}

(2)Demon

package com.ipc.lijiao.ipcserver;

import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.ServerSocket;
import java.net.Socket;

import javax.security.auth.Destroyable;

public class MainActivity extends AppCompatActivity {
    TextView show;
    Handler mhandler = new Handler();
    ServerSocket server;
    Socket socket;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        show = (TextView)findViewById(R.id.textView);
        AcceptClient();
    }

    private void AcceptClient()
    {
        new Thread()
        {
            @Override
            public void run()
            {
                    try
                    {
                        int port = 8919;
                        server = new ServerSocket(port);
                        while(true)
                        {
                            socket = server.accept();
                            String content = "";
                            BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
                            while (true)
                            {
                                String line = null;
                                line = reader.readLine();//读取客户端传来的数据
                                if (line == null)
                                    break;
                                content = content + line;
                            }
                            socket.shutdownInput();
                            final String context = content;
                            mhandler.post(new Runnable() {
                                @Override
                                public void run() {
                                    show.setText(context);
                                }
                            });
                            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
                            writer.write("客户端发送到服务端的消息为:"+context);
                            writer.flush();
                            socket.shutdownOutput();

                        }
                    }
                    catch(IOException e)
                    {
                        e.printStackTrace();
                    }
            }
        }.start();
    }

    public void onDestroy() {
        super.onDestroy();
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        mhandler.removeCallbacksAndMessages(null);
        mhandler = null;
        try {
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            server.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

猜你喜欢

转载自blog.csdn.net/lj1404536198/article/details/77460609