0
点赞
收藏
分享

微信扫一扫

【Java从零到架构师第1季】【网络编程】网络互连模型_TCP/IP协议_Java网络爬虫

Python百事通 2022-03-13 阅读 22
java网络

持续学习&持续更新中…

守破离


【Java从零到架构师第1季】【网络编程】网络互连模型_TCP/IP协议_Java网络爬虫

互联网

在这里插入图片描述

网络互连模型

网络互连模型:定义了网络该如何连接(计算机之间应该如何连接、通信、数据格式是什么样的、…)

在这里插入图片描述

注意:可以理解为TCP/IP协议模型中的网际层与OSI参考模型中的网络层是一个东西。

OSI七层参考模型:理论上的,比较复杂,不实用。

TCP/IP协议四层模型:实际应用。

五层模型:学习研究。

网络分层

在这里插入图片描述

在这里插入图片描述

HTTP请求过程

在这里插入图片描述

在这里插入图片描述

TCP/IP协议

在这里插入图片描述

TCP vs UDP

在这里插入图片描述

在这里插入图片描述

TCP数据

在这里插入图片描述

UDP数据

在这里插入图片描述

TCP—建立连接—三次握手

在这里插入图片描述

在这里插入图片描述

解释:

  • 首先,启动服务器,让服务器进入监听状态(监听客户端的连接请求)。
  • 客户端向服务器发送同步连接请求:SYN=1;seq=x
    • SYN(同步标识位):将SYN设置为1,代表告诉服务器,我想跟你同步数据,也就是建立连接。
    • seq(序列号):还需要发送一个序列号seq=x给服务器。
  • 服务器给客户端返回接受同步连接请求:SYN=1;ACK=1;seq=y;ack=x+1
    • SYN(同步标识位):服务器返回SYN=1,代表告诉客户端,没问题,我可以和你同步。
    • ACK(确认标识位):ACK=1,代表确认同步,并且还给你发送了确认号。
    • ack=x+1:ack就是确认号;这个x就是客户端向服务器发送同步连接请求时发送的那个序列号。
    • seq=y:还需要发送一个序列号seq=y给客户端。
  • 客户端向服务器发送确认连接信息:ACK=1;seq=x+1;ack=y+1
    • ACK(确认标识位):ACK=1,代表确认同步,并且还给你发送了确认号。
    • ack=y+1:ack就是确认号;这个y就是服务器给客户端返回接受同步连接请求时返回的那个序列号。
    • seq=x+1:将序列号seq=x+1发送给服务器。

总结:

  • 客户端与服务器之间的每次“沟通”都会携带序列号(每一条消息都必须得有序列号)。
  • 序列号是不断增加的,可以用来标识这是自己发送出去的第几条信息。
  • 在建立连接时:确认号(ack)=对方发送的序列号(seq)+1
  • 当连接已经建立完毕,在传输数据时,确认号就不一定是对方发送的序列号+1了,确认号可以为其他值。

TCP—释放连接—四次挥手

在这里插入图片描述

在这里插入图片描述

解释:

  • FIN(终止信号):FIN=1代表告诉对方,我想跟你断开连接。

总结:

  • 四次挥手释放连接时,客户端和服务器双方都需要向对方发送一次释放连接请求(双方都需要提出一次“分手”)并让对方确认。
  • 当然,第一次释放连接请求是由客户端向服务器发出的。

DNS服务器

在这里插入图片描述

Java—网络编程—Socket编程

以TCP为例:

TCPServet:

public class TCPServer {
    public static void main(String[] args) throws Exception {
        try (final ServerSocket serverSocket = new ServerSocket(8888)) {
            try (final Socket accept = serverSocket.accept()) {
                try (final InputStream is = accept.getInputStream();
                     final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                    byte[] bytes = new byte[10240];
                    int len;
                    while ((len = is.read(bytes)) != -1) {
                        baos.write(bytes, 0, len);
                    }
                    baos.flush();
                    final byte[] data = baos.toByteArray();
                    final String dataStr = new String(data, StandardCharsets.UTF_8);
                    System.out.println("服务器接受到的数据:\n" + dataStr);
                }
            }
        }
    }
}

TCPClient:

public class TCPClient {
    public static void main(String[] args) throws Exception {
        try (final Socket socket = new Socket("localhost", 8888)) {
            try (final OutputStream os = socket.getOutputStream()) {
                os.write("hello, tcp network programming!".getBytes(StandardCharsets.UTF_8));
            }
        }
    }
}

稍微改造一下服务器的代码:

public class TCPServer {
    public static void main(String[] args) throws Exception {
        try (final ServerSocket server = new ServerSocket(8888)) {
            while (true) {
                final Socket client = server.accept();
                new Thread(() -> {
                    try {
                        doClient(client);
                        client.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }).start();
            }
        }
    }

    private static void doClient(Socket client) {
        try (final InputStream is = client.getInputStream();
             final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            final byte[] bytes = new byte[10240];
            int len;
            while ((len = is.read(bytes)) != -1) {
                baos.write(bytes, 0, len);
            }
            baos.flush();
            final byte[] data = baos.toByteArray();
            final String dataStr = new String(data, StandardCharsets.UTF_8);
            final String clientAddr = client.getInetAddress().getHostAddress();
            System.out.println("服务器接受到【" + clientAddr + "】的数据:" + dataStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

让服务器可以给客户端响应数据:

TCPServer:

public class TCPServer {
    public static void main(String[] args) throws Exception {
        try (final ServerSocket server = new ServerSocket(8888)) {
            while (true) {
                final Socket client = server.accept();
                new Thread(() -> {
                    try {
                        doClient(client);
                        client.close();
                    } catch (IOException e) {
                    }
                }).start();
            }
        }
    }

    private static void doClient(Socket client) {
        try (
                final ByteArrayOutputStream baos = new ByteArrayOutputStream();
                final InputStream is = client.getInputStream();
                final OutputStream os = client.getOutputStream()
        ) {
            // 接收客户端的数据
            final byte[] bytes = new byte[10240];
            int len;
            while ((len = is.read(bytes)) != -1) {
                baos.write(bytes, 0, len);
            }
            baos.flush();
            final byte[] data = baos.toByteArray();
            final String dataStr = new String(data, StandardCharsets.UTF_8);
            final String clientAddr = client.getInetAddress().getHostAddress();
            System.out.println("服务器接受到【" + clientAddr + "】的数据:" + dataStr);
            // 接收完毕客户端发送过来的数据之后,就要关闭输入
            client.shutdownInput();

            // 给客户端响应数据
            os.write("Hi, I am Server. I have accepted your data!".getBytes(StandardCharsets.UTF_8));
            client.shutdownOutput();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

TCPClient:

public class TCPClient {
    public static void main(String[] args) throws Exception {
        try (final Socket socket = new Socket("localhost", 8888)) {
            try (
                    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    final OutputStream os = socket.getOutputStream();
                    final InputStream is = socket.getInputStream()
            ) {
                // 给服务器写数据
                os.write("hello, tcp network programming!".getBytes(StandardCharsets.UTF_8));
                // 给服务器的内容都写完之后,要关闭输出
                socket.shutdownOutput();

                // 接收服务器返回的数据
                final byte[] bytes = new byte[10240];
                int len;
                while ((len = is.read(bytes)) != -1) {
                    baos.write(bytes, 0, len);
                }
                baos.flush();
                final byte[] data = baos.toByteArray();
                final String dataStr = new String(data, StandardCharsets.UTF_8);
                System.out.println("客户端接受到服务器返回的数据:" + dataStr);
                socket.shutdownInput();
            }
        }
    }
}

Java—网络爬虫

https://jsoup.org/

在这里插入图片描述

爬取URL:https://ext.se.360.cn/webstore/category

爬取HTML元素示例:

在这里插入图片描述

爬取代码:

在这里插入图片描述

爬取结果:

在这里插入图片描述

我们完全可以将爬取到的结果弄成JSON或者其他形式的数据,保存到文件或数据库中,以供之后使用。

参考

小码哥-李明杰: Java从0到架构师①零基础高效率入门.


本文完,感谢您的关注支持!


举报

相关推荐

0 条评论