# TestTcpUdp_Android **Repository Path**: leesonzhong/test_tcp_udp_android ## Basic Information - **Project Name**: TestTcpUdp_Android - **Description**: Android平台上测试TCP和UDP工具app。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 2 - **Created**: 2021-07-05 - **Last Updated**: 2024-07-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一、简单了解TCP/UDP - 计算机与网络设备要相互通信,双方就必须基于相同的方法。比如,如何探测到通信目标、由哪一边先发起通信、使用哪种语言进行通信、怎样结束通信等规则都需要事先确定。不同的硬件、操作系统之间的通信,所有的这一切都需要一种规则。而我们就把这种规则称为协议(protocol)。 - TCP/IP 是互联网相关的各类协议族的总称,比如:TCP,UDP,IP,FTP,HTTP,ICMP,SMTP 等都属于 TCP/IP 族内的协议。 - 当一台计算机想要与另一台计算机通讯时,两台计算机之间的通信需要畅通且可靠,这样才能保证正确收发数据。例如,当你想查看网页或查看电子邮件时,希望完整且按顺序查看网页,而不丢失任何内容。当你下载文件时,希望获得的是完整的文件,而不仅仅是文件的一部分,因为如果数据丢失或乱序,都不是你希望得到的结果,于是就用到了TCP。 - TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的RFC 793定义。TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构,你可以把它想象成排水管中的水流 - UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。 - 用自己的话简单概括一下。tcp连接可靠,需要多次握手,点对点,发送方要和接收方通信确认数据传输情况。udp连接不可靠,支持一对一、一对多、多对一和多对多,发送方只管发送并不理会接收方,实时性高。 - 安卓系统已经提供了tcp和udp的封装方法,在java.net包中,只需要学会怎样调用API,不需要理会里面的底层原理。 # 二、使用TCP/UDP - 参考网址:Java利用TCP协议实现客户端与服务器通信【附通信源码】。https://blog.csdn.net/weixin_44985880/article/details/107130365 - 参考网址:Java基于UDP实现服务器和多客户端之间的通信。https://www.imooc.com/article/16708 - 其实安卓开发使用tcp和udp非常简单,弄这个工程主要是写一个简单通用的tcp/udp测试工具,在弄其它网络通信开发前可以先用这个工具来测试通信和协议是否正常。 - 新建安卓工程,在AndroidMainfast.xml添加网络权限 ``` ``` - 网络通信一定要放在后台线程,所以可以实现Runable接口。然后用线程池进行管理。 - 编写TCP服务器代码,创建TcpServerRunnable,实现Runable接口 ``` public class TcpServerRunnable implements Runnable ``` - 编写TCP服务器代码,根据端口创建TCP服务端ServerSocket对象,然后等待客户端的接收 ``` server = new ServerSocket(port); client = server.accept(); ``` - 编写TCP服务器代码,接收客户端的的信息 ``` nputStream in = client.getInputStream(); //获取到客户端的输入流 if (in.available()>0) { byte[] b = new byte[1024]; //定义字节数组 int len = in.read(b); } ``` - 编写TCP服务器代码,发送信息给客户端 ``` OutputStream out = client.getOutputStream(); out.write(senddata_a); ``` - 编写TCP服务器代码,如果要关掉服务器端,断开连接 ``` if (server != null){ try { server.close(); } catch (IOException ex) { ex.printStackTrace(); } } server = null; ``` - 编写TCP客户端代码,创建TcpClientRunnable,实现Runable接口 ``` public class TcpClientRunnable implements Runnable ``` - 编写TCP客户端代码,根据TCP客户端Socket对象,根据IP和端口进行连接。也可以创建Socket对象时传入IP和端口。 ``` clientSocket = new Socket(); clientSocket.connect(new InetSocketAddress(InetAddress.getByName(serverIp),port), ``` - 编写TCP客户端代码,接收服务端发送的信息 ``` nputStream in = client.getInputStream(); if (in.available()>0) { byte[] b = new byte[1024]; //定义字节数组 int len = in.read(b); } ``` - 编写TCP客户端代码,发送信息给服务端 ``` OutputStream out = client.getOutputStream(); out.write(senddata_a); ``` - 编写TCP客户端代码,关掉客户端,断开连接 ``` if (client != null){ try { client.close(); } catch (IOException ex) { ex.printStackTrace(); } } client = null; ``` - UDP和TCP有很大不同是没有握手连接,所以java语言的UDP方法没看到有连接判断的,只要有地址和端口就可以发送。所以如果要判断连接状态,应该开发人员制定协议通过发送数据和接收数据来判断连接是否超时断开。 - 编写UDP服务端代码,创建UdpServerRunnable,实现Runable接口 ``` public class UdpServerRunnable implements Runnable ``` - 编写UDP服务端代码,根据端口创建DatagramSocket对象 ``` server = new DatagramSocket(port); ``` - 编写UDP服务端代码,接收客户端的的信息。创建DatagramPacket用来接收,如果接收信息成功后,packet会包含客户端的ip和端口和接收的数据。 ``` byte[] data = new byte[1024];//创建字节数组,指定数据报的大小 DatagramPacket packet = new DatagramPacket(data, data.length); if (server.isConnected()) { server.receive(packet);//此方法在收到数据之前会一直阻塞 } ``` - 编写UDP服务端代码,发送客户端信息。要指定IP和端口 ``` //1.定义客服端的地址、端口号、数据 InetAddress address = InetAddress.getByName(ip); //2.创建数据报,包含响应的数据信息 DatagramPacket packet = new DatagramPacket(data, data.length, address, port); //3.响应客服端 server.send(packet); ``` - 编写UDP服务端代码,关掉客户端,断开连接 ``` if (server != null){ server.close(); } server = null; ``` - 创建线程池来管理,实现了Runable接口的对象传递给execute方法进行执行。 ``` ExecutorService cachedThreadPool = Executors.newCachedThreadPool(); cachedThreadPool.execute(runnable); ``` # 三、测试使用 - pc端使用SocketTool工具配合app进行调试 - tcp服务端ServerSocket可以设置连接的客户端个数。 - 关于判断远程端是否断开,没有好的方法。socket提供的 isClosed()、isConnected()、isInputStreamShutdown()、isOutputStreamShutdown()方法好像都是本地端的,所以没有方法判断远程端的。通过网上查找资料,使用sendUrgentData来判断,发现不行。发送tcp的,可以通过发送的结果判断是否连接正常,udp只能用户通过自定义心跳包接收超时判断连接是否正常,都是需要定时发送数据进行判断。 - tcp服务端无法检测到 客户端的断开,只能通过发送数据判断连接状态。检测到客户端断开后,重新监听客户端的连接。 - tcp客户端无法检测到服务端端的断开,只能通过发送数据判断连接状态。检测到服务端断开后,客户端也断开 - udp服务端无法检测到客户端的连接和断开,只能断开自己的连接。发送时会使用接收到数据的客户端的ip和端口,如果没有接受过数据,无法发送。DatagramSocket的isConnected会一直是false - android网络操作要在后台线程,tcp因为可以使用InputStream的available()方法判断是否有接收数据,所以接收和发送可以放在同一个线程。udp因为接收会阻塞,无法预先判断是否有数据,所以要新建线程发送数据。java有提供NIO实现接收不阻塞,但我没有尝试过。 - Udp客户端虽然设置了要连接的服务端ip和端口,但是接收不限制来源,只是发送时设置为服务端ip和端口。