Android进程间通信之Socket
来源:互联网 发布:淘宝网卡包 编辑:程序博客网 时间:2024/05/29 19:57
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进程间通信
- web项目中获取spring的bean对象
- 您所不知道的nil/Nil/NULL/NSNull的空与空
- 基于稀疏矩阵的k近邻(KNN)实现
- 文章标题
- HBaseCon 2013: Using Coprocessors to Index Columns in an Elasticsearch Cluster
- Android进程间通信之Socket
- Java容器类的深入理解
- 数据挖掘之七种常用的方法
- JSON入门学习
- Majority Element 主要的元素
- 数据分析与可视化工具小谈
- UVa 213 Message Coding
- c语言解析json
- 技术发展瓶颈的突破