Android进程间通信之Socket
来源:互联网 发布:ubuntu.com 编辑:程序博客网 时间:2024/06/06 02:19
Socket也称为“套接字”,是网络通信中的概念,它分为流式套接字和用户数据报套接字两种,分别对应于网络传输控制层中的TCP和UDP协议。
TCP协议是面向连接的协议,提供稳定的双向通信功能,TCP连接的建立需要经过“三次握手”才能完成,为了提供稳定的数据传输功能,其本身提供了超时重传机制,因此具有很高的稳定性。
而UDP是无连接的,提供不稳定的单向通信功能,当然UDP也可以实现双向通信功能。
在性能上,UDP具有更好的效率,其缺点是不保证数据一定能够正确传输,尤其是在网络拥塞的情况下。
TCP协议中的三次握手和四次挥手:
建立TCP需要三次握手才能完成连接,而断开连接需要四次挥手。
连接过程:
1.客户端发送连接请求报文
2.服务端接收到连接请求后回复ACK报文,并为这次连接分配资源
3.客户端接收到ACK报文后也向服务端发送ACK报文,并分配资源
经过上面三次握手,TCP连接就建立成功了。
断开过程:断开连接请求可以是客户端发起,也可以是服务端发起,这里以客户端发起为例
1.客户方发送FIN报文
2.服务端接收到FIN报文后,发送ACK给客户端,客户端接收到消息后进入FIN_WAIT状态等待服务端的FIN报文
3.服务端确定数据已经发送完成则向客户端发送FIN报文
4.客户端收到FIN报文后发送ACK报文给服务端,并进入TIME_WAIT状态,如果服务端没有收到ACK报文则可以重传。服务端收到ACK后就知道可以断开连接了。客户端等待2MSL(最大报文段生存时间)后依然没有收到回复,则证明服务端已正常关闭,客户端也可以关闭连接了。
经过上面四次挥手,连接就断开了。
为什么连接的时候是三次握手,关闭的时候却是四次握手?
答:因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭Socket,所以只能先回复一个ACK报文,告诉客户端收到了客户端发送的FIN报文。只有等服务端所有的报文都发送完了,服务端才能发送FIN报文,因此不能一起发送。故需要四次握手。
为什么TIME_WAIT状态需要经过2MSL才能返回CLOSE状态?
答:网络是不可靠的,有可能造成最后一个ACK丢失,所有TIME_WAIT状态就是用来重发可能丢失的ACK报文的。
例子:聊天工具,服务端每收到一个连接请求后就创建一个Socket连接,这样服务端就可以和不同的客户端通信了。服务端每收到一条消息就自动回复一条消息。
服务端代码:
- public class SocketTcpService extends Service {
- private boolean mIsServerRunning;
- private String[] mDefaultMsgs = new String[] { "hehe", "haha", "heihei" };
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public void onCreate() {
- super.onCreate();
- mIsServerRunning = true;
- new Thread(){
- public void run() {
- ServerSocket serverSocket = null;
- try {
- // 监听本地8688接口
- serverSocket = new ServerSocket(8688);
- } catch (Exception e) {
- e.printStackTrace();
- }
- while(mIsServerRunning) {
- try {
- // 接收客户端请求
- final Socket socket = serverSocket.accept();
- System.out.println("accept");
- new Thread() {
- public void run() {
- try {
- responseClient(socket);
- } catch (IOException e) {
- e.printStackTrace();
- }
- };
- }.start();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- };
- }.start();
- }
- private void responseClient(Socket socket) throws IOException {
- // 接收客户端消息
- BufferedReader in = new BufferedReader(new InputStreamReader(
- socket.getInputStream()));
- // 向客户端发送消息
- PrintWriter out = new PrintWriter(new BufferedWriter(
- new OutputStreamWriter(socket.getOutputStream())), true);
- System.out.println("欢迎来到聊天室");
- while (mIsServerRunning) {
- // 读取客户端发来的消息
- String str = in.readLine();
- // 判断客户端断开连接的方法很多,这里用输入流是否为null判断
- if (str == null) {
- break;
- }
- int i = new Random().nextInt(mDefaultMsgs.length);
- String msg = mDefaultMsgs[i];
- // 服务端发送消息
- out.println("服务端:" + msg);
- }
- System.out.println("客户端退出");
- out.close();
- in.close();
- socket.close();
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- mIsServerRunning = false;
- }
- }
客户端代码:客户端和服务端是在同一个应用中的不同进程
- public class MainActivity extends Activity {
- private Socket mSocket;
- private Button mButton;
- private TextView mText;
- private PrintWriter mWrite;
- private String[] mDefaultMsgs = new String[] { "xixi", "houhou", "aa" };
- private Handler mHandler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- switch (msg.what) {
- case 0:
- mButton.setEnabled(true);
- break;
- case 1:
- mText.setText((String)msg.obj);
- break;
- }
- super.handleMessage(msg);
- };
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mButton = (Button) findViewById(R.id.btn);
- mText = (TextView) findViewById(R.id.text);
- mButton.setOnClickListener(mClickListener);
- Intent service = new Intent(this, SocketTcpService.class);
- startService(service);
- startConnect();
- }
- private OnClickListener mClickListener = new OnClickListener() {
- @Override
- public void onClick(View v) {
- int i = new Random().nextInt(mDefaultMsgs.length);
- String msg = "客户端:" + mDefaultMsgs[i];
- if (!TextUtils.isEmpty(msg) && mWrite != null) {
- // 客户端发消息
- mWrite.println(msg);
- mText.setText(mText.getText() + msg + "\n");
- }
- }
- };
- private void startConnect() {
- new Thread() {
- public void run() {
- while (mSocket == null) {
- try {
- mSocket = new Socket("localhost", 8688);
- mWrite = new PrintWriter(
- new BufferedWriter(new OutputStreamWriter(
- mSocket.getOutputStream())), true);
- mHandler.sendEmptyMessage(0);
- System.out.println("连接成功");
- } catch (Exception e) {
- SystemClock.sleep(1000);
- System.out.println("连接失败,重新连接");
- }
- }
- try {
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(mSocket.getInputStream()));
- while (!MainActivity.this.isFinishing()) {
- // 读取服务端发送来的消息
- String msg = reader.readLine();
- msg = mText.getText() + msg + "\n";
- if (msg != null) {
- mHandler.obtainMessage(1,msg).sendToTarget();
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- };
- }.start();
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (mSocket != null) {
- try {
- mSocket.shutdownInput();
- mSocket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- android 进程间通信之SOCKET通信
- Android进程间通信(IPC)之Socket
- Android进程间通信之Socket
- Android进程间通信之--Socket
- Android进程间通信之Socket
- 进程间通信之:socket
- python socket之进程间通信
- 进程间通信之 Unix Domain Socket
- 进程间通信之-socket编程原理
- IPC进程间通信之Socket
- android 使用socket完成进程间通信
- Android 使用Socket完成进程间通信
- Android 使用Socket完成进程间通信
- android进程间通信ipc Socket (二)
- 进程间通信-socket
- 进程间通信---------socket
- socket进程间通信
- socket进程间通信
- 内联函数
- Android二维码ZXing开源框架的学习总结
- Postgresql Dblink相关函数
- arm linux 移植usb转串口驱动
- leetCode_字典树
- Android进程间通信之Socket
- Oracle - SQL学习笔记 1
- 自动取款机ATM取款系统 课题项目
- NYOJ 151 Biorhythms --剩余定理
- Scala入门到精通——第十四节 Case Class与模式匹配(一),scala入门到精通
- 换个思维透透气
- 一颗核桃的逆袭之路
- 【HDU】1087 - Super Jumping! Jumping! Jumping!(dp)
- PHP CI框架继承Smarty步骤及遇到的问题