🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] # InetAddress JDK中提供了一个InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法,下表中列出了InetAddress类的一些常用方法 ![](https://box.kancloud.cn/8cd241d3e01d88637f69ed4cb39f07c5_1234x436.jpg) 其中,前两个方法用于获得该类的实例对象,第一个方法用于获得表示指定主机的InetAddress对象,第二个方法用于获得表示本地的InetAddress对象。通过InetAddress对象便可获取指定主机名,IP地址等 ~~~ InetAddress local = InetAddress.getLocalHost(); InetAddress remote = InetAddress.getByName("pv.xinyuntec.com"); System.out.println("本机ip: "+local.getHostAddress()); System.out.println("xinyun的ip: "+remote.getHostAddress()); System.out.println("xinyun的主机: "+remote.getHostName()); ~~~ # UDP UDP是一种面向无连接的协议,因此,在通信时发送端和接收端不用建立连接。UDP通信的过程就像是货运公司在两个码头间发送货物一样。在码头发送和接收货物时都需要使用集装箱来装载货物,UDP通信也是一样,发送和接收的数据也需要使用“集装箱”进行打包,为此JDK中提供了一个DatagramPacket类,该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。 ## DatagramPacket 接收方 ![](https://box.kancloud.cn/a37351949c487bffe61f0ea7cebfe0ce_1146x102.jpg) 发送方 ![](https://box.kancloud.cn/20cd28d49e711e054ed85251e7d411c0_1422x106.jpg) 使用该构造方法在创建DatagramPacket对象时,不仅指定了封装数据的字节数组和数据的大小,还指定了数据包的目标IP地址(addr)和端口号(port)。该对象通常用于发送端,因为在发送数据时必须指定接收端的IP地址和端口号,就好像发送货物的集装箱上面必须标明接收人的地址一样。 **常用方法** ![](https://box.kancloud.cn/49d027ea62fd0214acbe91ee0f0be9ae_1426x352.jpg) ## DatagramSocket DatagramPacket数据包的作用就如同是“集装箱”,可以将发送端或者接收端的数据封装起来。然而运输货物只有“集装箱”是不够的,还需要有码头。在程序中需要实现通信只有DatagramPacket数据包也同样不行,为此JDK中提供的一个DatagramSocket类。DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包,发送数据的过程如下图所示。 ![](https://box.kancloud.cn/9edf5fd5a6f5c8dd22a07ef611e2515b_824x392.jpg) 在创建发送端和接收端的DatagramSocket对象时,使用的构造方法也有所不同 常用的构造方法 ![](https://box.kancloud.cn/5bdca4f0dac648e2ab1f40eca577a971_1536x540.jpg) 常用方法 ![](https://box.kancloud.cn/205773b445f5f0ba10d1d64a9bc26594_766x222.jpg) ## UDP网络程序(聊天室) **接收端** ~~~ //创建数据包传输对象,并绑定端口6000 DatagramSocket datagramSocket = new DatagramSocket(6000); //创建字节数组 byte[] data = new byte[1024]; while (true) { //创建数据包对象,传递字节数组 DatagramPacket datagramPacket = new DatagramPacket(data, data.length); //调用datagramSocket对象方法receive传递数据包 datagramSocket.receive(datagramPacket); //获取发送端的ip地址对象和端口 String ip = datagramPacket.getAddress().getHostAddress(); int port = datagramPacket.getPort(); int length = datagramPacket.getLength(); System.out.println(new String(data,0,length)+"..."+ip+":"+port); } //datagramSocket.close(); ~~~ **发送端** ~~~ Scanner sc = new Scanner(System.in); //创建DatagramSocket对象,数据包的发送和接收对象 DatagramSocket datagramSocket = new DatagramSocket(); //创建InetAddress对象,封装自己的ip地址 InetAddress inetAddress = InetAddress.getByName("127.0.0.1"); while (true) { String message = sc.nextLine(); byte[] date = message.getBytes(); DatagramPacket datagramPacket = new DatagramPacket(date, date.length, inetAddress, 6000); //发送数据包 datagramSocket.send(datagramPacket); } //关闭资源 //datagramSocket.close(); ~~~ # TCP UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据。 而TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。 在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。 ## ServerSocket 使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上(参数port就是端口号)。 ![](https://box.kancloud.cn/921e8eee576c1877b52ef57240726ff3_1002x118.jpg) ServerSocket的常用方法 ![](https://box.kancloud.cn/e344a223734324e43d055bf5f4c5a6c9_1074x252.jpg) ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行 ## Socket 用于实现TCP客户端程序 **构造方法** 该构造方法在创建Socket对象时,会根据参数去连接在指定地址和端口上运行的服务器程序,其中参数host接收的是一个字符串类型的IP地址 ![](https://box.kancloud.cn/bac58e6477827a629fa3c7ee0d375725_1398x128.jpg) 参数address用于接收一个InetAddress类型的对象,该对象用于封装一个IP地址。 ![](https://box.kancloud.cn/6f484499b9c72e22654cbe475cbd525f_1434x128.jpg) **常用方法** | 方法声明 | 功能描述 | | --- | --- | | int getPort() | 该方法返回一个int类型对象,该对象是Socket对象与服务器端连接的端口号 | | InetAddress getLocalAddress() | 该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成 InetAddress类型的对象返回 | | void close() | 该方法用于关闭Socket连接,结束本次通信。在关闭socket之前,应将与socket相关的所有的输入/输出流全部关闭,这是因为一个良好的程序应该在执行完毕时释放所有的资源 | | InputStream getInputStream() | 该方法返回一个InputStream类型的输入流对象,如果该对象是由服务器端的Socket返回,就用于读取客户端发送的数据,反之,用于读取服务器端发送的数据 | | OutputStream getOutputStream() | 该方法返回一个OutputStream类型的输出流对象,如果该对象是由服务器端的Socket返回,就用于向客户端发送数据,反之,用于向服务器端发送数据 | 在Socket类的常用方法中,getInputStream()和getOutStream()方法分别用于获取输入流和输出流。当客户端和服务端建立连接后,数据是以IO流的形式进行交互的,从而实现通信。 接下来通过一张图来描述服务器端和客户端的数据传输,如下图所示 ![](https://box.kancloud.cn/b672b5eb573013bdde82b6744e275b2e_1360x482.jpg) ## TCP实现文件上传 * 服务器端 ~~~ /* * 文件上传 服务器端 * */ public class TCPServer { public static void main(String[] args) throws IOException { //1,创建服务器,等待客户端连接 ServerSocket serverSocket = new ServerSocket(8888); Socket clientSocket = serverSocket.accept(); //显示哪个客户端Socket连接上了服务器 InetAddress ipObject = clientSocket.getInetAddress();//得到IP地址对象 String ip = ipObject.getHostAddress(); //得到IP地址字符串 System.out.println("小样,抓到你了,连接我!!" + "IP:" + ip); //7,获取Socket的输入流 InputStream in = clientSocket.getInputStream(); //8,创建目的地的字节输出流 D:\\upload\\192.168.74.58(1).jpg BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream("D:\\upload\\192.168.74.58(1).jpg")); //9,把Socket输入流中的数据,写入目的地的字节输出流中 byte[] buffer = new byte[1024]; int len = -1; while((len = in.read(buffer)) != -1){ //写入目的地的字节输出流中 fileOut.write(buffer, 0, len); } //-----------------反馈信息--------------------- //10,获取Socket的输出流, 作用:写反馈信息给客户端 OutputStream out = clientSocket.getOutputStream(); //11,写反馈信息给客户端 out.write("图片上传成功".getBytes()); out.close(); fileOut.close(); in.close(); clientSocket.close(); //serverSocket.close(); } } ~~~ * 编写客户端,完成上传图片 ~~~ /* * 文件上传 客户端 * * public void shutdownOutput() 禁用此Socket的输出流,间接的相当于告知了服务器数据写入完毕 */ public class TCPClient { public static void main(String[] args) throws IOException { //2,创建客户端Socket,连接服务器 Socket socket = new Socket("192.168.74.58", 8888); //3,获取Socket流中的输出流,功能:用来把数据写到服务器 OutputStream out = socket.getOutputStream(); //4,创建字节输入流,功能:用来读取数据源(图片)的字节 BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream("D:\\NoDir\\test.jpg")); //5,把图片数据写到Socket的输出流中(把数据传给服务器) byte[] buffer = new byte[1024]; int len = -1; while ((len = fileIn.read(buffer)) != -1){ //把数据写到Socket的输出流中 out.write(buffer, 0, len); } //6,客户端发送数据完毕,结束Socket输出流的写入操作,告知服务器端 socket.shutdownOutput(); //-----------------反馈信息--------------------- //12,获取Socket的输入流 作用: 读反馈信息 InputStream in = socket.getInputStream(); //13,读反馈信息 byte[] info = new byte[1024]; //把反馈信息存储到info数组中,并记录字节个数 int length = in.read(info); //显示反馈结果 System.out.println( new String(info, 0, length) ); //关闭流 in.close(); fileIn.close(); out.close(); socket.close(); } } ~~~