Socket通信的实现

匆匆过客 提交于 2020-03-03 06:55:16

使用Socket通信需要在AndroidManifest中声明以下权限:

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

其次是不能在主线程中访问网络,因为网络操作很可能是耗时的,从而抛出异常(android.os.NetworkOnMainThreadException)。因此创建socket连接,发送/接收消息都需要在线程中进行,消息UI更新可以使用handle实现。

聊天室实现
在远程Service建立一个TCP服务,在主界面中连接TCP服务,连接上之后服务端与多个客户端响应。

服务端的代码实现:
通过判断服务端输入流的返回值,当客户端断开连接后,服务端的输入流会返回null,这时就知道客户端已经退出。

public class TCPServerService extends Service {

    public final static String TAG = TCPServerService.class.getSimpleName();

    private boolean mIsServiceDestroyed = false; // 用来标识服务是否停止向客户端发送消息

    private String[] definedMsg = MsgConstants.DEFINED_MSG_LIST;

    public TCPServerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return null;
    }

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

    @Override
    public void onDestroy() {
        // 当服务被销毁时,停止向客户端发送消息
        mIsServiceDestroyed = true;
        super.onDestroy();
    }

    private class TcpServer implements Runnable {
        @Override
        public void run() {
            ServerSocket mClientSocket = null;
            try {
                mClientSocket = new ServerSocket(8688); // 建立服务端
                Log.d(TAG, "start server,listener to 8688 port");
            } catch (IOException e) {
                e.printStackTrace();
            }

            while (!mIsServiceDestroyed) {
                try {
                    final Socket client = mClientSocket.accept(); // 等待接收请求,创建socket连接
                    Log.d(TAG, "waiting client connect 8688 port");
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            responseClient(client); // 响应客户端
                        }
                    }).start();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void responseClient(Socket client) {
        BufferedReader reader = null;
        PrintWriter writer = null;
        try {
            // reader接收客户端发送的消息
            reader = new BufferedReader(
                    new InputStreamReader(client.getInputStream()));

            // writer向客户端发送消息
            writer = new PrintWriter(new BufferedWriter(
                    new OutputStreamWriter(client.getOutputStream())), true);

            // 当服务未被销毁,就持续响应客户端
            while (!mIsServiceDestroyed) {
                String msg = reader.readLine();
                if (msg == null) {
                    break;
                }
                if (!TextUtils.isEmpty(msg)) {
                    writer.println("service received - " + msg + "\n");
                    Log.d(TAG, "service received - " + msg);
                }
                int i = new Random().nextInt(definedMsg.length);
                writer.println("service send - " + definedMsg[i] + "\n");
                Log.d(TAG, "service send - " + definedMsg[i]);
            }
            writer.println("client quit." + "\n");
            Log.d(TAG, "client quit.");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (reader != null) {
                    reader.close();
                }
                if (writer != null) {
                    writer.close();
                }
                if (client != null) {
                    client.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

客户端示例代码如下:

public class TCPClientActivity extends AppCompatActivity implements View.OnClickListener {

    public static final String TAG = TCPClientActivity.class.getSimpleName();

    private Button mSendBtn;
    private TextView mMsgTextView;
    private EditText mMsgEditText;

    private Socket mClientSocket = null;
    private PrintWriter mPrintWriter; // 客户端发送消息
    private BufferedReader mReader; // 客户端接收消息

    // 客户端发送或接收的消息在handleMessage中更新UI
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MsgConstants.SOCKET_CONNECT:
                    mSendBtn.setEnabled(true);
                    break;
                case MsgConstants.SOCKET_RECEIVE_MSG:
                    mMsgTextView.setText(mMsgTextView.getText() + "\n" + (String) msg.obj);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tcpclient);
        mSendBtn = (Button) findViewById(R.id.send_btn);
        mMsgEditText = (EditText) findViewById(R.id.edit_msg);
        mMsgTextView = (TextView) findViewById(R.id.text_msg);
        Intent service = new Intent(this, TCPServerService.class);
        startService(service);
        new Thread(new Runnable() {
            @Override
            public void run() {
                connectTCPServer();
            }
        }).start();
        mSendBtn.setOnClickListener(TCPClientActivity.this);
    }

    private void connectTCPServer() {
        while (mClientSocket == null) {
            try {
                // 建立socket连接
                mClientSocket = new Socket("127.0.0.1", 8688);
                mPrintWriter = new PrintWriter(new BufferedWriter(
                        new OutputStreamWriter(mClientSocket.getOutputStream())), true);
                handler.sendEmptyMessage(MsgConstants.SOCKET_CONNECT);
                Log.d(TAG, "connect tcp server success");
            } catch (IOException e) {
                /**
                 采用超时重连的策略,每次连接失败后都会重新建立连接。
                 为降低重试机制的开销,加入休眠机制,每次重试的时间间隔为1000ms。
                 */
                SystemClock.sleep(1000);
                Log.d(TAG, "connect tcp server failed,retry....");
            }
        }
        receiveMsg();
    }

    private void receiveMsg() {
        try {
            mReader = new BufferedReader(
                    new InputStreamReader(mClientSocket.getInputStream()));
            while (!TCPClientActivity.this.isFinishing()) {
                String msg = mReader.readLine();
                if (msg != null && !TextUtils.isEmpty(msg)) {
                    Log.d(TAG, "client received - " + msg);
                    String time = formatTime(System.currentTimeMillis());
                    String showedMsg = "client received " + time + " - " + msg + "\n";
                    handler.obtainMessage(MsgConstants.SOCKET_RECEIVE_MSG, showedMsg).sendToTarget();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onClick(View view) {
        if (view == mSendBtn) {
            final String editMsg = mMsgEditText.getText().toString();
            if (!TextUtils.isEmpty(editMsg) && mPrintWriter != null) {
                mMsgEditText.setText("");
                String time = formatTime(System.currentTimeMillis());
                final String showedMsg = "client send " + time + " - " + editMsg + "\n";
                mMsgTextView.setText(mMsgTextView.getText() + showedMsg);
                sendMsg(showedMsg);
                Log.d(TAG, "client send - " + editMsg);
            }
        }
    }

    private void sendMsg(final String showedMsg) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                mPrintWriter.println(showedMsg);
            }
        }).start();
    }

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

    }

    private String formatTime(long time) {
        return new SimpleDateFormat("(HH:mm:ss)").format(new Date(time));
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!