【Java SE】二十、网络编程

这里记录一些 Java 中关于网络的基本流程,不含计算机网络基本知识,更多内容得去学 JavaWeb。

InetAddress 类

在 Java 中使用 InetAddress 类代表 IP 地址,该类的构造器私有化,要想获得实例,常调用提供的静态方法来返回对象

try {
    InetAddress inet1 = InetAddress.getByName("www.acfun.cn"); // 也可以直接输入IP
    InetAddress inet2 = InetAddress.getLocalHost(); // 获取本机地址
    System.out.println(inet1);
    System.out.println(inet1.getHostName()); // 获取域名
    System.out.println(inet1.getHostAddress()); // 获取IP地址
} catch (UnknownHostException e) {
    e.printStackTrace();
}

TCP网络编程

IP + 端口号 = Socket,下面这个例子展示了 Socket 类的使用以及客户端和服务端的信息交流:

public class TCPTest {
    // 客户端
    @Test
    public void client() {
        Socket socket = null;
        OutputStream os = null;
        InputStream is = null;
        try {
            InetAddress inet = InetAddress.getLocalHost();
            socket = new Socket(inet, 8021); // 通过Socket与本机服务端建立连接,端口号由服务端设定
            os = socket.getOutputStream(); // 获取输出流

            os.write("Where are you?".getBytes()); // 发送信息,若是文件,则可以用文件流先读取
            socket.shutdownOutput(); // 发送文件时,记得关闭数据输出,防止服务端一直接收

            is = socket.getInputStream(); // 获取字节输入流,接收来自服务端的反馈
            byte[] buffer = new byte[16];
            int len;
            while ((len = is.read(buffer)) != -1) {
                System.out.println("client <- " + new String(buffer, 0, len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally { // 记得关闭资源
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {e.printStackTrace();}
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {e.printStackTrace();}
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {e.printStackTrace();}
            }
        }
    }

    // 服务端
    @Test
    public void server() {
        ServerSocket ss = null;
        Socket socket = null;
        InputStream is = null;
        ByteArrayOutputStream baos = null;
        OutputStream os = null;
        try {
            ss = new ServerSocket(8021); // 建立服务端Socket
            socket = ss.accept(); // 接收客户端Socket
            is = socket.getInputStream(); // 获取字节流

            baos = new ByteArrayOutputStream(); // 用字节数组流接收
            byte[] buffer = new byte[16];
            int len;
            while ((len = is.read(buffer)) != -1) {
                baos.write(buffer, 0, len);
            }

            System.out.println("server <- " + baos.toString() + " <- " + socket.getInetAddress().getHostAddress()); // 获取客户端IP

            os = socket.getOutputStream(); // 获取字节输出流
            os.write("I'm here!".getBytes()); // 反馈信息
        } catch (IOException e) {
            e.printStackTrace();
        } finally { // 记得关闭资源
            if (ss != null) {
                try {
                    ss.close();
                } catch (IOException e) {e.printStackTrace();}
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {e.printStackTrace();}
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {e.printStackTrace();}
            }
            if (baos != null) {
                try {
                    baos.close();
                } catch (IOException e) {e.printStackTrace();}
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {e.printStackTrace();}
            }
        }
    }
}

UDP网络编程

UDP 是一种不可靠的无连接协议,效率高。下例展示了 DatagramSocket 类的使用以及发送端和接收端的信息交流:

public class UDPTest {
	// 发送端
    public void sender() throws IOException {
        DatagramSocket socket = new DatagramSocket(); // 创建socket
        byte[] data = "Hello,receiver!".getBytes();
        InetAddress inet = InetAddress.getLocalHost();
        DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet, 9090); // 打包成数据包
        socket.send(packet); // 发送
        socket.close();
    }

    // 接收端
    public void receiver() throws IOException {
        DatagramSocket socket = new DatagramSocket(9090); // 创建socket且声明端口
        byte[] buffer = new byte[32];
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
        socket.receive(packet); // 接收
        System.out.println(new String(packet.getData(), 0, packet.getLength()));
        socket.close();
    }
}

注:上面的例子简化了异常处理的部分,但不建议这样做

URL编程

Java 提供一个 URL 类来处理 url 的网络编程部分,常用方法如下表:

方法 说明
getProtocol() 获取该URL的协议名
getHost() 获取该URL的主机名
getPort() 获取该URL的端口号
getPath() 获取该URL的文件路径
getFile() 获取该URL的文件名
getQuery() 获取该URL的查询名

下例展示了 URL 类的使用:

public void URLTest() {
    URL url = new URL("https://www.acfun.cn/beauty3.jpg");
    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); // 打开url
    urlConnection.connect(); // 连接url
    InputStream is = urlConnection.getInputStream(); // 获取输入流
    FileOutputStream fos = new FileOutputStream("beauty3.jpg");
    byte[] buffer = new byte[1024];
    int len;
    while((len = is.read(buffer)) != -1) {
    	fos.write(buffer, 0, len);
    }
    is.close();
    fos.close();
    urlConnection.disconnect(); // 记得关
}