IPC进程间通信的使用(五)——Socket

进程间通信除了Bundle,文件共享,Messenger,ContentProvider,ADIL就是Socket了。这里同样简单记录一下。
Socket也被叫做套接字,是网络通信中的概念,分为TCP和UDP。
Socket通信需要声明权限

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

不能在主线程访问网络,因为这会导致程序抛出异常android.os.NetworkOnMainThreadException。网络操作也可能会比较耗时,如果放在主线程,就会影响程序的效率,从这个角度来说,也不应该放在主线程。

服务端

/**
 * Created by Kevin on 2019/4/10<br/>
 * Blog:https://blog.csdn.net/student9128<br/>
 * Describe:<br/>
 */
public class TCPServerService extends Service {
    private static final String TAG = "TCPServerService";
    private boolean mIsServiceDestroyed = false;
    private String[] mDefinedMessage = new String[]{"Hello!",
            "What is your name,please?",
            "It is Sunny,Wonderful!",
            "Do your know,i can chat with more than one person",
            "I am AI"};

    @Override
    public void onCreate() {
        super.onCreate();
        new Thread(new TCPServer()).start();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mIsServiceDestroyed = true;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private class TCPServer implements Runnable {

        @Override
        public void run() {
            ServerSocket serverSocket = null;
            try {
                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() {
                            super.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("Welcome to Chatting Room!!!");
            while (!mIsServiceDestroyed) {
                String str = in.readLine();
                Log.d(TAG, "msg from client:" + str);
                if (str == null) {
                    //客户端断开连接
                    break;
                }
                int i = new Random().nextInt(mDefinedMessage.length);
                String msg = mDefinedMessage[i];
                out.println(msg);
                Log.d(TAG, "send:" + msg);
            }

            in.close();
            out.close();
            client.close();
        }
    }
}

客户端

Socket既可以实现进程间通信,也可实现设备间通信。这里将代码修改了一下,添加了ip输入框。通过两个设备来进行通信。

/**
 * Created by Kevin on 2019/4/10<br/>
 * Blog:https://blog.csdn.net/student9128<br/>
 * Describe:<br/>
 */
public class TCPClientActivity extends AppCompatActivity implements View.OnClickListener {
    private static final int MESSAGE_RECEIVE_NEW_MSG = 101;
    private static final int MESSAGE_SOCKET_CONNECTED = 102;
    private Button mSendButton, mOKButton;
    private TextView mMessageTextView;
    private EditText mMessageEditText;
    private EditText mIPEditText;
    private PrintWriter mPrintWriter;
    private Socket mClientSocket;
    private String TAG = getClass().getSimpleName();
    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(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;
            }
        }
    };

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tcp_client);
        mMessageTextView = findViewById(R.id.msg_text);
        mMessageEditText = findViewById(R.id.msg_edit);
        mSendButton = findViewById(R.id.btn_send);
        mSendButton.setOnClickListener(this);
        mIPEditText = findViewById(R.id.et_ip);
        mOKButton = findViewById(R.id.btn_ok);
        mOKButton.setOnClickListener(this);
        Intent intent = new Intent();
        intent.setComponent(new ComponentName("com.kevin.serverclient", "com.kevin.serverclient.TCPServerService"));
        intent.setAction("com.kevin.server.tcp");
        if (Build.VERSION.SDK_INT >= 26) {//8.0以后修改了启动方式
            startForegroundService(intent);
        } else {
            startService(intent);
        }

    }

    @Override
    protected void onDestroy() {//Activity退出的时候,关闭Client的Socket
        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() {
                        super.run();
                        mPrintWriter.println(msg);
                    }
                }.start();
                mMessageEditText.setText("");
                String time = formatDateTime(System.currentTimeMillis());
                String shownMsg = "self " + time + ":" + msg + "\n";
                mMessageTextView.setText(mMessageTextView.getText() + shownMsg);
            }
        }
        if (v == mOKButton) {
            final String trim = mIPEditText.getText().toString().trim();
            if (!TextUtils.isEmpty(trim)) {
                new Thread() {
                    @Override
                    public void run() {
                        super.run();
                        connectTCPServer(trim);
                    }
                }.start();
            }
        }
    }

    private String formatDateTime(long time) {
        return new SimpleDateFormat("(HH:mm:ss)").format(new Date(time));
    }

    private void connectTCPServer(String ip) {
        Socket socket = null;
        while (socket == null) {
            try {
                socket = new Socket(ip, 8688);
                mClientSocket = socket;
                mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
                mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
                Log.d(TAG, "connect server successfully");
            } catch (IOException e) {
                e.printStackTrace();
                SystemClock.sleep(1000);
                Log.d(TAG, "connect tcp server failed, retrying...");
            }
        }
        try {//服务连接成功,代码中不断去获取服务端的消息
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while (!TCPClientActivity.this.isFinishing()) {
                String msg = br.readLine();
                Log.d(TAG, "receive: " + msg);
                if (msg != null) {
                    String time = formatDateTime(System.currentTimeMillis());
                    String shownMsg = "server " + time + ":" + msg + "\n";
                    mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, shownMsg).sendToTarget();
                }
            }
            mPrintWriter.close();
            br.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值