之前写过一些关于TCP和UDP数据传输的代码,比如使用TCP传输音视频数据包,P2P打洞中使用UDP等。写好之后就直接丢下了,没有总结下都。最近准备找工作,再拿来温习下。
暂时把自己的定位很明确,就是android应用层的开发,所以关于TCP/UDP的实现细节,暂时也不想去深究。但是心里清楚这个必须去看的,有时间推荐大家看看《TCP/IP详解》,或者网上有很多大牛的总结。
new Socket(ip, prot);我们可以通过上面的方式创建一个socket,如果失败,会抛出IOException。参数中的IP和Port是目标服务器的IP和端口号。若你想得到本地的IP和端口可通过这个socket拿到。当然,创建socket还有多种构造方法,比如 new Socket(proxy) ,如果有需要你可以查阅相关说明。
InputStream is = mSocket.getInputStream(); OutputStream out = mSocket.getOutputStream();通过输出流,我们可以使用is.read(receiveBuffer)和out.write(data);来进行数据的收发。这里给两个简单实例:
@Override public void execute() { try { int count = is.read(receiveBuffer); if (count == -1) { notifyError(); } byte[] data = getPacket(receiveBuffer, count, is); mReceiverQueue.put(data); } catch (InterruptedException e) { e.printStackTrace(); notifyError(); } catch (IOException e) { e.printStackTrace(); notifyError(); } }假如我们的数据包协议格式如下:
@Override public void execute() { try { byte[] data = mSenderQueue.take(); out.write(data); } catch (InterruptedException e) { e.printStackTrace(); notifyError(); } catch (IOException e) { e.printStackTrace(); notifyError(); } }mSenderQueue和mReceiverQueue一样,都是阻塞队列。发送的时候,我们从队列中取出要发送的数据,然后通过输出流写入即可。这个地方比发送简单了一些。可能你已经注意到,我的发送和接收都用了阻塞队列,这个原因就是考虑到大量数据的时候做一个缓冲,如果没有缓冲,可能导致代码的阻塞。另外就是当我们的阻塞队列充满的时候可以手动丢弃一些数据,这个就是具体应用了。
try { ServerSocket serverSocket = new ServerSocket(9559); while (true) { Socket socket = serverSocket.accept(); // new ServiceSocketThread(socket).start(); } } catch (Exception e) { e.printStackTrace(); }因为服务端不可能只与一个客户端连接,因此上面的代码写在一个死循环中。拿到socket之后起一个新的线程来处理这个socket。
这个东西用的很少,就是当初测试P2P的时候用过。能想到的问题就是数据大小的问题,比如发送数据我们的数据定义为多大合适。但是最后没有实际的项目验证,在此也不好回答。先贴一段代码出来:
public class UDPServer extends BaseThread { /** 发送队列大小 */ public static final int SENDQUEUESIZE = 10; /** 接收队列大小 */ public static final int RECEIVEQUEUESIZE = 10; /** TCP接收缓存大小 */ public static final int RECEIVERBUFFERSIZE = 1024; /** UDP接收缓存大小 */ public static final int RECEIVERPACKETSIZE = 1024 * 64; private int count = 0; private DatagramPacket receivePacket; private DatagramSocket mSocket; @Override public boolean prepare() { receivePacket = new DatagramPacket(new byte[RECEIVERPACKETSIZE], RECEIVERPACKETSIZE); try { mSocket = new DatagramSocket(9559); } catch (SocketException e) { System.out.println(String.format("udp connect init error: %s", e.getMessage())); return false; } return true; } @Override public void execute() { try { mSocket.receive(receivePacket); byte[] data = receivePacket.getData(); int length = receivePacket.getLength(); int offset = receivePacket.getOffset(); System.out.print(++count + String.format("length:%d|%d, offset:%d, data: %s \n", length, data.length, offset, new String(data, "gbk"))); System.out.println(data[1024]); } catch (SocketException e) { System.out.println(String.format("udp connect init error: %s", e.getMessage())); } catch (IOException e) { System.out.println(String.format("udp connect init error: %s", e.getMessage())); } } }byte[] data = receivePacket.getData();这个地方拿到的data是缓冲区的大小,他们地址是样的,这个大家可以试试就知道。至于这个data中有多少数据,就需要我们通过receivePacket.getLength();拿到。