最近一个Android项目中用到了Socket编程,主要是实现UDP通信。这里,用一个demo示例Socket编程过程。 ## 一、什么是Socket?
日常生活中,浏览器的进程与web服务器通信、QQ进程与服务器或你好友所在的QQ进程通信,这些都得靠socket。Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求。具体关于Socket,网上有很多相关的内容,可自行查找学习。
二、Socket编程流程
可以把Socket看作一种特殊的文件,如同操作文件一样我们去操作Socket。过程大致是:open—write/read—close。
三、Android中使用Socket编程实现TCP、UDP通信
因为TCP是可靠连接,而UDP属于不可靠连接,所以从速度上将UDP要快于TCP,但是TCP较UDP更稳定可靠。具体TCP、UDP的实现过程以及区别,也有很多可查阅的资料。
在Android中,Socket类位于java.net.Socket包中,UDP通信所需要使用的两个类DatagramSocket、DatagramPacket分别位于java.net.DatagramSocket和java.net.DatagramPacket包中。接下来,我们编写服务端和客户端程序来体验Android中的Socket编程。
TCP/UDP通信需要声明INTERNET权限,代码如下:
<uses-permission android:name="android.permission.INTERNET" />
客户端开启分别开启两个线程(TCP、UDP)用于与服务端不间断通信,服务端同样开启两个线程(绑定不同的端口号)用于接收客户端(TCP、UDP)发送的数据并返回相应的数据。步骤(以TCP为例)分为以下几步:
Android中TCP通信主要使用InputStream和OutputStream实现。
客户端: 1、 创建客户端套接字(指定服务器端IP地址与端口号) 2、 连接(Android 创建Socket时会自动连接) 3、 与服务器端进行通信 4、 关闭套接字
代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| new Thread(new Runnable() { @Override public void run() { while(true){ try { char[] buffer = new char[24]; Socket mSocket = new Socket("10.0.2.12", 8891); BufferedWriter mBufferedWriter = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream())); mBufferedWriter.write("TCP call request " + (++call_no) + "_"); mBufferedWriter.flush(); BufferedReader mBufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream())); String tmpString = null; if(mBufferedReader.read(buffer) > 0){ tmpString = new String(buffer); } Message msg = mHandler.obtainMessage(); msg.what = 0; msg.obj = tmpString; mHandler.sendMessage(msg); mBufferedReader.close(); mBufferedWriter.close(); mSocket.close(); Thread.sleep(1000); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();
|
服务器端: 1、 创建服务器端套接字并绑定到一个端口上 2、 套接字设置监听模式等待连接请求(阻塞) 3、 接受连接请求后进行通信 4、 返回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| new Thread(new Runnable() { public void run() { try { ServerSocket mServerSocket = new ServerSocket(8891); while(true){ char[] buffer = new char[1024]; Socket client = mServerSocket.accept(); BufferedReader mBufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream())); if(mBufferedReader.read(buffer) > 0){ System.out.println(new String(buffer)); } BufferedWriter mBufferedWriter = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); mBufferedWriter.write("(TCP)server return " + (++call_no) + "_"); mBufferedWriter.flush(); mBufferedReader.close(); mBufferedWriter.close(); client.close(); } } catch (IOException e) { e.printStackTrace(); } } }).start();
|
UDP通信是把数据打包成数据包发送的。主要使用DatagramSocket和DatagramSocket对象来实现,DatagramSocket是使用UDP方式通信时的Socket类,DatagramPacket是用来将数据打包的类,打包完成后由DatagramSocket对象发送数据包到指定的主机的端口上。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| new Thread(new Runnable() { @Override public void run() { DatagramSocket mDatagramSocket = null; DatagramPacket mDatagramPacket = null; String sendData = null; String receiveData = null; try { mDatagramSocket = new DatagramSocket(8893); while(true){ sendData = "UDP call request " + (++udp_call_no) + "_"; byte[] receiveMsg = new byte[1024]; mDatagramPacket = new DatagramPacket(sendData.getBytes(), sendData == null ? 0 : sendData.length(), InetAddress.getByName("10.0.2.12"), 8892); mDatagramSocket.send(mDatagramPacket); mDatagramPacket = new DatagramPacket(receiveMsg, receiveMsg.length); mDatagramSocket.receive(mDatagramPacket); receiveData = new String(mDatagramPacket.getData(), mDatagramPacket.getOffset(), mDatagramPacket.getLength()); Message msg = mHandler.obtainMessage(); msg.what = 1; msg.obj = receiveData; mHandler.sendMessage(msg); Thread.sleep(1000); } } catch (SocketException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start();
|
服务端通过DatagramSocket类的receive(DatagramPacket packet)方法接收发送过来的数据包,运行到这个方法时,会发生阻塞,直到接收到数据包。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| new Thread(new Runnable() { public void run() { DatagramSocket mDatagramSocket = null; DatagramPacket mDatagramPacket = null; String receiveData = null; String sendData = null; try { mDatagramSocket = new DatagramSocket(8892); while(true){ sendData = "(UDP)server return " + (++udp_call_no) + "_"; byte[] receiveMsg = new byte[1024]; mDatagramPacket = new DatagramPacket(receiveMsg, receiveMsg.length); mDatagramSocket.receive(mDatagramPacket); receiveData = new String(mDatagramPacket.getData(), mDatagramPacket.getOffset(), mDatagramPacket.getLength()); System.out.println(receiveData); mDatagramPacket = new DatagramPacket(sendData.getBytes(), sendData == null ? 0 : sendData.length(), InetAddress.getByName("10.0.2.16"), 8893); mDatagramSocket.send(mDatagramPacket); } } catch (SocketException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }).start();
|
四、完整代码
https://github.com/whilu/AndroidUtils/tree/master/SocketDemo