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连接,这样服务端就可以和不同的客户端通信了。服务端每收到一条消息就自动回复一条消息。

服务端代码:

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class SocketTcpService extends Service {  
  2.   
  3.     private boolean mIsServerRunning;  
  4.     private String[] mDefaultMsgs = new String[] { "hehe""haha""heihei" };  
  5.   
  6.     @Override  
  7.     public IBinder onBind(Intent intent) {  
  8.         return null;  
  9.     }  
  10.   
  11.     @Override  
  12.     public void onCreate() {  
  13.         super.onCreate();  
  14.         mIsServerRunning = true;  
  15.         new Thread(){  
  16.             public void run() {  
  17.                 ServerSocket serverSocket = null;  
  18.                 try {  
  19.                     // 监听本地8688接口  
  20.                     serverSocket = new ServerSocket(8688);  
  21.                 } catch (Exception e) {  
  22.                     e.printStackTrace();  
  23.                 }  
  24.                 while(mIsServerRunning) {  
  25.                     try {  
  26.                         // 接收客户端请求  
  27.                         final Socket socket = serverSocket.accept();  
  28.                         System.out.println("accept");  
  29.                         new Thread() {  
  30.                             public void run() {  
  31.                                 try {  
  32.                                     responseClient(socket);  
  33.                                 } catch (IOException e) {  
  34.                                     e.printStackTrace();  
  35.                                 }  
  36.                             };  
  37.                         }.start();  
  38.                     } catch (IOException e) {  
  39.                         e.printStackTrace();  
  40.                     }  
  41.                 }  
  42.             };  
  43.         }.start();  
  44.     }  
  45.   
  46.     private void responseClient(Socket socket) throws IOException {  
  47.         // 接收客户端消息  
  48.         BufferedReader in = new BufferedReader(new InputStreamReader(  
  49.                 socket.getInputStream()));  
  50.         // 向客户端发送消息  
  51.         PrintWriter out = new PrintWriter(new BufferedWriter(  
  52.                 new OutputStreamWriter(socket.getOutputStream())), true);  
  53.         System.out.println("欢迎来到聊天室");  
  54.         while (mIsServerRunning) {  
  55.             // 读取客户端发来的消息  
  56.             String str = in.readLine();  
  57.             // 判断客户端断开连接的方法很多,这里用输入流是否为null判断  
  58.             if (str == null) {  
  59.                 break;  
  60.             }  
  61.             int i = new Random().nextInt(mDefaultMsgs.length);  
  62.             String msg = mDefaultMsgs[i];  
  63.             // 服务端发送消息  
  64.             out.println("服务端:" + msg);  
  65.         }  
  66.         System.out.println("客户端退出");  
  67.         out.close();  
  68.         in.close();  
  69.         socket.close();  
  70.     }  
  71.   
  72.     @Override  
  73.     public void onDestroy() {  
  74.         super.onDestroy();  
  75.         mIsServerRunning = false;  
  76.     }  
  77.   
  78. }  


客户端代码:客户端和服务端是在同一个应用中的不同进程

[java] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public class MainActivity extends Activity {  
  2.   
  3.     private Socket mSocket;  
  4.     private Button mButton;  
  5.     private TextView mText;  
  6.     private PrintWriter mWrite;  
  7.     private String[] mDefaultMsgs = new String[] { "xixi""houhou""aa" };  
  8.     private Handler mHandler = new Handler() {  
  9.         public void handleMessage(android.os.Message msg) {  
  10.             switch (msg.what) {  
  11.             case 0:  
  12.                 mButton.setEnabled(true);  
  13.                 break;  
  14.             case 1:  
  15.                 mText.setText((String)msg.obj);  
  16.                 break;  
  17.             }  
  18.             super.handleMessage(msg);  
  19.         };  
  20.     };  
  21.   
  22.     @Override  
  23.     protected void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.activity_main);  
  26.   
  27.         mButton = (Button) findViewById(R.id.btn);  
  28.         mText = (TextView) findViewById(R.id.text);  
  29.         mButton.setOnClickListener(mClickListener);  
  30.         Intent service = new Intent(this, SocketTcpService.class);  
  31.         startService(service);  
  32.         startConnect();  
  33.     }  
  34.   
  35.     private OnClickListener mClickListener = new OnClickListener() {  
  36.           
  37.         @Override  
  38.         public void onClick(View v) {  
  39.             int i = new Random().nextInt(mDefaultMsgs.length);  
  40.             String msg = "客户端:" + mDefaultMsgs[i];  
  41.             if (!TextUtils.isEmpty(msg) && mWrite != null) {  
  42.                 // 客户端发消息  
  43.                 mWrite.println(msg);  
  44.                 mText.setText(mText.getText() + msg + "\n");  
  45.             }  
  46.         }  
  47.     };  
  48.   
  49.     private void startConnect() {  
  50.         new Thread() {  
  51.             public void run() {  
  52.                 while (mSocket == null) {  
  53.                     try {  
  54.                         mSocket = new Socket("localhost"8688);  
  55.                         mWrite = new PrintWriter(  
  56.                                 new BufferedWriter(new OutputStreamWriter(  
  57.                                         mSocket.getOutputStream())), true);  
  58.                         mHandler.sendEmptyMessage(0);  
  59.                         System.out.println("连接成功");  
  60.                     } catch (Exception e) {  
  61.                         SystemClock.sleep(1000);  
  62.                         System.out.println("连接失败,重新连接");  
  63.                     }  
  64.                 }  
  65.                 try {  
  66.                     BufferedReader reader = new BufferedReader(  
  67.                             new InputStreamReader(mSocket.getInputStream()));  
  68.                     while (!MainActivity.this.isFinishing()) {  
  69.                         // 读取服务端发送来的消息  
  70.                         String msg = reader.readLine();  
  71.                         msg = mText.getText() + msg + "\n";  
  72.                         if (msg != null) {  
  73.                             mHandler.obtainMessage(1,msg).sendToTarget();  
  74.                         }  
  75.                     }  
  76.                 } catch (IOException e) {  
  77.                     e.printStackTrace();  
  78.                 }  
  79.             };  
  80.         }.start();  
  81.     }  
  82.   
  83.     @Override  
  84.     protected void onDestroy() {  
  85.         super.onDestroy();  
  86.         if (mSocket != null) {  
  87.             try {  
  88.                 mSocket.shutdownInput();  
  89.                 mSocket.close();  
  90.             } catch (IOException e) {  
  91.                 e.printStackTrace();  
  92.             }  
  93.         }  
  94.     }  
  95.   

0 0
原创粉丝点击