Android进程间通信(IPC)之Socket

Socket也被称为“套接字”编程,它分为流式套接字和用户数据套接字两种,分别对应于网络传输控制中层中TCP和UDP协议。TCP协议是面向连接的协议,提供稳定的双向通信功能,TCP连接的建立需要经过”三次握手”才能实现,为了实现稳定的数据传输功能,其本身提供了超时重传机制,具有很高的稳定性。UDP是无连接的,提供不稳定的单向通信功能,当然UDP也可以实现双向通信功能,在性能上,UDP就有更好的效率,其缺点是不能保证数据一定传输正确,尤其是网络拥塞的情况下。
演示一个Socket聊天的程序:

服务端

package com.app.service;

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.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class TcpService extends Service {
    private boolean mIsServiceDestoryed = false;
    private String[] mDefinedMessage = new String[] { "你好", "hello", "辛苦了" };
    private ServerSocket mServerSocket;

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

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

    class TcpThread implements Runnable {

        @Override
        public void run() {
            try {
                //服务端在8688这个端口监听
                mServerSocket = new ServerSocket(8688);
            } catch (IOException e) {
                e.printStackTrace();
                return;
            }

            while (!mIsServiceDestoryed) {
                try {
                    //一个阻塞的方法,当有客户端Socket时会运行
                    final Socket socket = mServerSocket.accept();
                    new Thread() {
                        @Override
                        public void run() {
                            responseClient(socket);
                        }
                    }.start();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

        }

    }
    //服务端相应客户端
    private void responseClient(Socket socket) {
        try {
            //读取客户端发来的消息
            BufferedReader in = new BufferedReader(new InputStreamReader(
                    socket.getInputStream()));
            //用于向客户端发送消息
            PrintWriter out = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(socket.getOutputStream())), true);
            out.println("欢迎来到聊天室!");
            while (!mIsServiceDestoryed) {
                String str = in.readLine();//通信连接后,客户端不发消息,这个方法会一直阻塞
                Log.e("tag", "客户端消息:====" + str);
                if (str == null) {
                    break;
                }
                int i = new Random().nextInt(mDefinedMessage.length);
                String msg = mDefinedMessage[i];
                out.println(msg);//向客户端发送消息
            }
            //客户端连接断开后,要关闭数据流
            in.close();
            out.close();
            socket.close();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onDestroy() {
        mIsServiceDestoryed = true;//停止线程
        super.onDestroy();
    }
}

客户端
先看布局代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#fff"
    android:orientation="vertical" >

    <EditText
        android:id="@+id/et_recore"
        android:layout_width="fill_parent"
        android:layout_height="200dip"
        android:gravity="top|left"
        android:text="聊天记录:\n" >
    </EditText>

    <EditText
        android:id="@+id/et_send_content"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="输入要发送的内容" >
    </EditText>

    <Button
        android:id="@+id/btn_send"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送"
        android:textColor="#000" />

</LinearLayout>

java代码:

package com.app.client;

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.io.UnsupportedEncodingException;
import java.net.Socket;

import android.app.Activity;
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.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends Activity implements OnClickListener {
    private static final int MESSAGE_RECEIVE_NEW_MSG = 1;
    private static final int MESSAGE_SOCKET_CONNECTED = 2;
    private Button mButton_Send;
    private EditText mEditText01, mEditText02;
    private PrintWriter mPintWriter;
    private Socket mClientSocket;

    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case MESSAGE_RECEIVE_NEW_MSG:
                mEditText01.setText(mEditText01.getText() + (String) msg.obj);
                break;
            case MESSAGE_SOCKET_CONNECTED:
                mButton_Send.setEnabled(true);
                mEditText02.setEnabled(true);
                break;

            default:
                break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton_Send = (Button) findViewById(R.id.btn_send);
        mEditText01 = (EditText) findViewById(R.id.et_recore);
        mEditText02 = (EditText) findViewById(R.id.et_send_content);
        mButton_Send.setEnabled(false);
        mButton_Send.setOnClickListener(this);
        //开启服务
        Intent i = new Intent("com.app.service");
        startService(i);
        new Thread() {
            @Override
            public void run() {
                connectTCPServer();
            }
        }.start();
    }

    protected void connectTCPServer() {
        Socket socket = null;
        //while里面使用了超时重连策略
        while (socket == null) {
            try {
                socket = new Socket("localhost", 8688);
                mClientSocket = socket;
                mPintWriter = new PrintWriter(new BufferedWriter(
                        new OutputStreamWriter(socket.getOutputStream())), true);
                mHandler.sendEmptyMessage(MESSAGE_SOCKET_CONNECTED);
            } catch (Exception e) {
                SystemClock.sleep(1000);
            }
        }
        try {
            //用于读取服务端的消息
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    mClientSocket.getInputStream(), "utf-8"));
            while (!MainActivity.this.isFinishing()) {
                String msg = br.readLine();//读取
                Log.e("tag", "服务端消息:====" + msg);
                if (msg != null) {
                    String showeMsg = "server : " + msg + "\n";
                    mHandler.obtainMessage(MESSAGE_RECEIVE_NEW_MSG, showeMsg)
                            .sendToTarget();
                }
            }
            //关闭资源
            mPintWriter.close();
            br.close();
            socket.close();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onClick(View v) {
        String msg = mEditText02.getText().toString();
        if (!TextUtils.isEmpty(msg) && mPintWriter != null) {
            mPintWriter.println(msg);
            mEditText02.setText("");
            String showMsg = "client : " + msg + "\n";
            mEditText01.setText(mEditText01.getText() + showMsg);
        }
    }

    @Override
    protected void onDestroy() {
        if (mClientSocket != null) {
            try {
                mClientSocket.shutdownInput();
                mClientSocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        super.onDestroy();
    }
}

客户端和服务端联网需要权限:

  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值