JAVA 笔记 12 网络

网络编程

基本概念

    计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来的,实现资源共享和数据传输的系统。网络编程就是编写程序使互联网的两个(或多个)设备(如计算机)之间进行数据传输。

百度百科:分类 | 分层 | IP | 端口 | 套接字 | TCP | UDP | URL | URI

InetAddress 类

InetAddress 类,表示IP地址。

常用方法

  • byte[] getAddress() :返回原始 IP 地址;
  • static InetAddress getByName(String host) :在给定主机名的情况下确定主机的 IP 地址;
  • String getHostAddress() :返回 IP 地址字符串;
  • String getHostName() :获取此 IP 地址的主机名;
  • static InetAddress getLocalHost() :返回本地主机。

InetSocketAddress 类

InetSocketAddress类,实现 IP套接字地址(IP 地址 + 端口号)。

构造方法

  • InetSocketAddress(InetAddress addr, int port) :根据 IP 地址和端口号创建套接字地址;
  • InetSocketAddress(int port) :创建套接字地址,其中 IP 地址为通配符地址,端口号为指定值;
  • InetSocketAddress(String hostname, int port) :根据主机名和端口号创建套接字地址。

常用方法

  • InetAddress getAddress() :获取 InetAddress;
  • String getHostName() :获取 hostname;
  • int getPort() :获取端口号。

TCP网络编程

Socket 类

Socket 类,实现客户端套接字,套接字指的是两台设备之间通讯的端点。

构造方法

public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。

常用方法
  • public InputStream getInputStream() : 返回此套接字的输入流;
  • public OutputStream getOutputStream() : 返回此套接字的输出流;
  • public void close() :关闭此套接字;
  • public void shutdownOutput() : 禁用此套接字的输出流。

ServerSocket 类

ServerSocket类,实现了服务器套接字,该对象等待通过网络的请求。

构造方法

public ServerSocket(int port) :使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号。

常用方法
  • public Socket accept() :侦听并接受连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接。

代码实现

示例1
  • 客户端向服务端发送消息;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

@Slf4j
public class TCPDomo {

    private static final String HOST = "127.0.0.1";

    private static final Integer PORT = 8080;

    /**
     * 服务端
     */
    @Test
    public void server() {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream inputStream = null;
        ByteArrayOutputStream outputStream = null;
        try {
            // 创建服务端的ServerSocket,指明自己的端口号
            serverSocket = new ServerSocket(PORT);

            // 调用accept接收到来自于客户端的socket
            // 阻塞式监听,会一直等待客户端的接入
            socket = serverSocket.accept();

            // 获取socket的输入流
            inputStream = socket.getInputStream();

            // 读取输入流中的数据
            outputStream = new ByteArrayOutputStream();
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
            log.info("收到了来自于客户端 [{}] 的消息:{}", socket.getInetAddress().getHostName(), outputStream.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 客户端
     */
    @Test
    public void client() {
        Socket socket = null;
        OutputStream os = null;
        try {
            // 创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
            InetAddress inet = InetAddress.getByName(HOST);
            socket = new Socket(inet, PORT);
            // 获取一个输出流,用于写出要发送的数据
            os = socket.getOutputStream();
            // 写出数据
            os.write("你好,我是客户端!".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

}
示例2
  • 客户端向服务端发送消息;
  • 服务端发向客户端回复消息;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

@Slf4j
public class TCPDomo {

    private static final String HOST = "127.0.0.1";

    private static final Integer PORT = 8080;

    /**
     * 服务端
     */
    @Test
    public void server() {
        ServerSocket serverSocket = null;
        Socket socket = null;
        InputStream inputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        OutputStream outputStream = null;
        try {
            // 创建服务端的ServerSocket,指明自己的端口号
            serverSocket = new ServerSocket(PORT);
            // 调用accept接收到来自于客户端的socket
            // 阻塞式监听,会一直等待客户端接入
            socket = serverSocket.accept();
            // 获取socket的输入流
            inputStream = socket.getInputStream();

            // 读取输入流中的数据
            byteArrayOutputStream = new ByteArrayOutputStream();
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, len);
            }
            log.info("收到了来自于客户端 [{}] 的消息:{}", socket.getInetAddress().getHostName(), byteArrayOutputStream.toString());
            // ===========================回复==========================================
            // 获取一个输出流,写出回复给客户端
            outputStream = socket.getOutputStream();
            // 写出数据
            outputStream.write("你好,我是服务端".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 客户端
     */
    @Test
    public void client() {
        Socket socket = null;
        OutputStream outputStream = null;
        ByteArrayOutputStream byteArrayOutputStream = null;
        InputStream inputStream = null;
        try {
            // 创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
            InetAddress inet = InetAddress.getByName(HOST);
            socket = new Socket(inet, PORT);
            // 获取一个输出流,用于写出要发送的数据
            outputStream = socket.getOutputStream();
            // 写出数据
            outputStream.write("你好,我是客户端!".getBytes());
            // ==========================解析回复==================================
            // 首先必须通知服务器,我已经输出完毕了,不然服务端不知道什么时候输出完毕
            // 服务端的while循环会一直执行,会阻塞
            socket.shutdownOutput();
            // 获取输入流,用于读取服务端回复的数据
            inputStream = socket.getInputStream();
            byteArrayOutputStream = new ByteArrayOutputStream();
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, len);
            }
            log.info("收到了来自服务端的消息:{}", byteArrayOutputStream.toString());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (byteArrayOutputStream != null) {
                try {
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}  
示例3
  • 上传文件:客户端发送文件给服务端,服务端将文件保存在本地
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

@Slf4j
public class TCPDomo {

    private static final String HOST = "127.0.0.1";

    private static final Integer PORT = 8080;

    /**
     * 服务端
     */
    @Test
    public void server() {
        ServerSocket serverSocket = null;
        Socket socket = null;
        FileOutputStream fileOutputStream = null;
        InputStream inputStream = null;
        try {
            // 创建服务端的ServerSocket,指明自己的端口号
            serverSocket = new ServerSocket(PORT);
            // 调用accept接收到来自于客户端的socket
            //阻塞式监听,会一直等待客户端的接入
            socket = serverSocket.accept();
            // 创建一个文件输出流,用于将读取到的客户端上传的文件输出
            fileOutputStream = new FileOutputStream("image.jpg");
            // 获取socket的输入流
            inputStream = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            // 写出文件
            while ((len = inputStream.read(buffer)) != -1) {
                fileOutputStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 客户端
     */
    @Test
    public void client() {
        Socket socket = null;
        FileInputStream fileInputStream = null;
        OutputStream outputStream = null;
        try {
            // 创建Socket对象,它的第一个参数需要的是服务端的IP,第二个参数是服务端的端口
            InetAddress inet = InetAddress.getByName(HOST);
            socket = new Socket(inet, PORT);
            // 创建一个文件输入流,读取要上传的文件
            fileInputStream = new FileInputStream("D:/image.jpg");
            // 获取一个输出流,用于写出要发送的数据
            outputStream = socket.getOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            // 写出数据
            while ((len = fileInputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

UDP网络编程

对于UDP来说,严格意义上,并没有所谓的Server和Client。

java.net包给我们提供了两个类DatagramSocket(用于发送和接收数据报的套接字)和DatagramPacket(数据报的数据包。 )

DatagramSocket

构造方法

protected DatagramSocket()构造数据报套接字并将其绑定到本地主机上的任何可用端口;
protected DatagramSocket(int port)构造数据报套接字并将其绑定到本地主机上的指定端口;
protected DatagramSocket(int port, InetAddress laddr)创建一个数据报套接字,绑定到指定的本地地址。

DatagramPacket

构造方法

DatagramPacket(byte[] buf, int offset, int length)构造一个 DatagramPacket用于接收指定长度的数据报包到缓冲区中;
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)构造用于发送指定长度的数据报包到指定主机的指定端口号上。

常用方法

byte[] getData() :返回数据报包中的数据;
InetAddress getAddress():返回该数据报发送或接收数据报的计算机的IP地址;
int getLength():返回要发送的数据的长度或接收到的数据的长度。

代码实现

示例1
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

@Slf4j
public class UDPDemo {

    private static final String HOST = "127.0.0.1";

    private static final Integer PORT = 8080;

    /**
     * 接收方
     */
    @Test
    public void receive() throws IOException {
        // 创建一个socket,开放端口
        DatagramSocket socket = new DatagramSocket(PORT);
        byte[] buffer = new byte[1024];
        // 创建一个包接收数据
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
        // 接收数据
        socket.receive(packet);//阻塞式接收
        // 将数据包转换为字符串输出
        String msg = new String(packet.getData(), 0, packet.getLength());
        log.info("接收到消息:[{}]", msg);
        // 释放资源
        socket.close();
    }

    /**
     * 发送方
     */
    @Test
    public void send() throws IOException {
        // 创建一个socket
        DatagramSocket socket = new DatagramSocket();
        InetAddress inet = InetAddress.getByName(HOST);
        String msg = "你好,很高兴认识你!";
        byte[] buffer = msg.getBytes();
        // 创建一个包(要发送给谁)
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length, inet, PORT);
        // 发送包
        socket.send(packet);
        // 释放资源
        socket.close();
    }
    
}
示例2

完成在线咨询功能,学生和老师在线一对一交流(多线程)。

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

@Slf4j
public class UDPDemo {

    private static final String HOST = "127.0.0.1";

    private static final Integer PORT_1 = 8080;

    private static final Integer PORT_2 = 9090;

    /**
     * 发送方
     */
    class Sender implements Runnable {

        // 创建一个socket
        DatagramSocket socket = null;

        // 创建一个流 用于录入键盘的数据
        BufferedReader bufferedReader = null;

        // 发送数据目的地的IP
        private String toIP;

        // 发送数据目的地的端口
        private int toPort;

        public Sender(String toIP, int toPort) {
            this.toIP = toIP;
            this.toPort = toPort;
            try {
                // 创建一个socket
                socket = new DatagramSocket();
            } catch (SocketException e) {
                e.printStackTrace();
            }
            bufferedReader = new BufferedReader(new InputStreamReader(System.in));//从键盘录入数据到流中
        }

        @Override
        public void run() {
            // 循环发送数据
            while (true) {
                try {
                    //从流中读取数据
                    String msg = bufferedReader.readLine();
                    byte[] buffer = msg.getBytes();
                    InetAddress inet = InetAddress.getByName(toIP);
                    DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length, inet, toPort);
                    socket.send(packet);
                    // 如果发送了拜拜,则退出发送
                    if (msg.equals("拜拜")) {
                        break;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //释放资源
            if (socket != null) {
                socket.close();
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 接收方
     */
    class Receiver implements Runnable {
        // 创建一个socket
        DatagramSocket socket = null;

        // 接收方自己所在的端口
        private int fromPort;

        // 数据发送者的姓名
        private String msgFrom;

        public Receiver(int fromPort, String msgFrom) {
            this.fromPort = fromPort;
            this.msgFrom = msgFrom;
            try {
                socket = new DatagramSocket(fromPort);//创建一个socket
            } catch (SocketException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void run() {
            // 循环接收
            while (true) {
                try {
                    byte[] buffer = new byte[1024 * 8];
                    DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
                    socket.receive(packet);
                    String msg = new String(packet.getData(), 0, packet.getLength());
                    log.info("{}:{}", msgFrom, msg);
                    if (msg.equals("拜拜")) {//如果接收到的数据为拜拜,则退出接收
                        break;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 释放资源
            socket.close();
        }
    }

    /**
     * 老师线程
     */
    @Test
    public void receive() {
        new Thread(new Sender(HOST, PORT_1)).start();
        new Thread(new Receiver(PORT_2, "学生")).start();
    }

    /**
     * 学生线程
     */
    @Test
    public void send() {
        new Thread(new Sender(HOST, PORT_2)).start();
        new Thread(new Receiver(PORT_1, "老师")).start();
    }

}

URL 类

构造方法

  • URL(String spec):根据 String 表示形式创建 URL 对象;
  • URL(String protocol, String host, int port, String file):根据指定协议名、主机名、端口号和文件名创建 URL 对象;
  • URL(String protocol, String host, String file):根据指定的协议名、主机名和文件名创建 URL。

常用方法

  • String getProtocol():获取此 URL的协议名称;
  • String getHost():获取此 URL 的主机名;
  • int getPort():获取此 URL 的端口号;
  • String getPath():获取此 URL 的文件路径;
  • String getFile():获取此 URL 的文件名;
  • String getQuery():获取此 URL的查询部分;
  • URLConnection openConnection():返回一个URLConnection实例,表示与URL引用的远程对象的URL 。
    • URLConnection类中有一个方法:InputStream getInputStream():返回从此打开的连接读取的输入流。

示例

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

@Slf4j
public class URLDemo {

    @Test
    public void visit() throws MalformedURLException {
        URL url = new URL("https://www.baidu.com/");
        log.info("获取协议名: {}", url.getProtocol());
        log.info("获取主机名: {}", url.getHost());
        log.info("获取端口号: {}", url.getPort());
        log.info("获取文件路径: {}", url.getPath());
        log.info("获取文件名: {}", url.getFile());
        log.info("获取查询名: {}", url.getQuery());
    }

    @Test
    public void download() throws IOException {
        // 下载地址
        URL url = new URL("https://i0.hdslb.com/bfs/activity-plat/static/20190409/7d3fbe1b994526c1fae2b51bb7f2b633/S114GfcFE.png");
        // 连接到这个资源 HTTP
        HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
        InputStream is = urlConnection.getInputStream();
        FileOutputStream fos = new FileOutputStream("bilibili.png");
        byte[] buffer = new byte[1024];
        int len=0;
        while ((len=is.read(buffer))!=-1){
            fos.write(buffer, 0, len);
        }
        // 释放资源
        urlConnection.disconnect();
        is.close();
        fos.close();
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 狂神说Java全部笔记是一部非常受欢迎的Java学习资料。这份笔记主要由狂神根据自己多年的Java开发经验总结而成,包含了Java开发中的各个方面。 首先,笔记中涵盖了Java的基础知识,如Java的发展历史、安装配置、基本语法、数据类型、运算符等。这些内容对于初学者来说非常重要,可以帮助他们快速入门。 其次,笔记中还介绍了Java的面向对象编程思想,包括封装、继承、多态等概念,以及如何使用类、对象、方法等构建自己的程序。这是Java开发的核心内容,通过深入学习这些知识,可以更好地掌握Java编程。 此外,狂神还在笔记中详细介绍了Java中常用的类库和API,如集合框架、IO操作、多线程、网络编程等。这些内容对于提升开发效率和扩展能力非常有帮助。 最后,笔记中还包含了一些实战项目的案例分析,可以帮助读者将所学的知识应用到实际项目中。通过动手实践,读者可以更好地理解和掌握Java开发的各个环节。 总的来说,狂神说Java全部笔记是一份非常全面和实用的学习资料,适合各个阶段的Java学习者。无论是初学者还是有一定经验的开发者,都可以从中获益良多。通过学习这份笔记,读者可以打下良好的Java基础,掌握Java开发的核心知识,提高开发能力,从而更好地应对实际项目的需求。 ### 回答2: 狂神说Java是一份关于Java编程语言的全面笔记,内容涵盖了Java的基础知识、面向对象编程、集合框架、多线程编程、Java IO、数据库编程等方面的内容。 在Java的基础知识部分,狂神详细介绍了Java的发展历史、Java的安装配置、Java的数据类型、运算符、控制语句等基本知识,并给出了许多实际案例进行演示和讲解,帮助读者理解和掌握这些概念和技能。 在面向对象编程部分,狂神详细介绍了Java中的类和对象、封装性、继承性、多态性等面向对象的特性,以及如何利用这些特性进行软件开发,包括类的设计、构造方法、方法重载和方法重写等内容。 在集合框架部分,狂神讲解了Java中的各种集合类,如ArrayList、LinkedList、HashMap等,并介绍了它们的使用方法和常见应用场景,以及集合的遍历和排序等相关操作。 在多线程编程部分,狂神详细介绍了Java中的线程概念、线程的创建和启动、线程同步与通信等内容,并提供了一些实际案例来演示多线程编程的实际应用。 在Java IO部分,狂神讲解了Java中的输入输出流、文件操作、字符流和字节流等内容,并提供了一些示例代码进行演示。 在数据库编程部分,狂神介绍了Java中如何使用JDBC进行数据库的连接和操作,包括建立连接、执行SQL语句、事务处理等内容,并提供了一些实际案例进行演示。 总之,狂神说Java是一份非常全面、详细的Java编程笔记,适合初学者和有一定基础的Java开发者阅读和学习。通过阅读狂神说Java,读者可以系统地了解和掌握Java编程的基本知识和技能,为以后的Java开发打下良好的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值