• Java笔记15


    网络编程基础

    • 计算机网络: 两台或者更多台计算机组成的网络, 在同一个网络中, 任意两台中计算机可以直接通信, 所有计算机都需要遵守同一种网络协议.
    • 计算机接入互联网, 必须使用TCP/IP协议
    • TCP/IP协议泛指互联网协议, 最重要的两个协议: TCP协议和IP协议

    IP地址

    • IP地址用于唯一标识一个网络接口
    • IPV4: 采用32位地址; IPV6: 采用128位地址
    • 127.0.0.1: 指向本机
    • 公网IP地址和内网IP地址. 公网ip可以直接访问, 内网ip只能内部网络访问(10.*.*.*)``192.168.*.*
    • 如果有一个网卡, 并接入了网络, 就有了一个本机地址, 和ip地址, 可以使用这个ip地址接入网络
    • 如果有两个网卡就可以分别接入不同的网络, 例如路由器和交换机
    • 如果两台计算机位于同一个网络, 那么他们可以直接通信, 因为ip地址的前段是相同的, 也就是网络号是相同的.
    • 网络号: ip地址通过子网掩码过滤后得到的.
    IP = 101.202.99.2
    Mask = 255.255.255.0
    Network = IP & Mask = 101.202.99.0
    
    • 网络号相同, 证明在同一个网路, 可以直接通信
    • 网络号不同, 需要路由器/交换机进行通讯. 也就是网关
    • 网关的作用是链接多个网络
    • 路由: 负责把一个网络的数据包发送到另一个网络

    域名

    • 域名解析服务器DNS负责把域名翻译成对应的IP, 客户端再根据IP访问
    • nslookup [url]
    • nsloopkup www.baidu.com
    Server:  192.168.16.1
    Address: 192.168.16.1#53
    
    Non-authoritative answer:
    www.baidu.com canonical name = www.a.shifen.com.
    Name: www.a.shifen.com
    Address: 61.135.169.121
    Name: www.a.shifen.com
    Address: 61.135.169.125
    

    网络模型

    • OSI网络模型为了简化网络各层操作, 提供标准接口便于实现和维护
    • 模型从上到下:
      • 应用层: 提供应用程序之间的通讯
      • 表示层: 处理数据格式, 加解密等
      • 会话层: 负责建立和维护会话
      • 传输层: 提供端到端的可靠传输
      • 网络层: 负责根据目标地址选择路由来传输数据
      • 链路层和物理层: 负责把数据进行分片并真正通过物理网络传输
    • TCP协议:
      • 应用层; 传输层; IP层; 网络接口层;

    常用协议

    • IP协议: 一个分组协议, 不保证可靠传输

    • TCP协议: 建立在IP协议之上, 传输控制协议, 面向链接的协议, 支持可靠传输和双向通信

    • ip协议只负责发送数据包, 不保证顺序和正确性;

    • tcp协议负责控制数据包传输, 在传输数据之前要先建立连接, 建立链接后才能传输数据, 传输完成后, 断开链接

    • tcp通过接受确认, 超时重传等机制保证数据的可靠传输

    • tcp允许双向通信, 即通信的双方可以同时发送和接受数据

    • tcp协议是应用最广的协议, http和smtp都是建立在tcp协议之上

    • udp协议是一种数据报文协议, 无连接协议, 不保证可靠传输. 在通讯前不需要建立连接, 因此传输效率比tcp高, 并比tcp协议简单; 传输的数据, 需要能够忍受丢失.

    TCP编程

    • 一个应用程序通过一个Socket建立一个远程连接, Socket内部通过TCP/IP协议把数据传输到网络
    • Socket, TCP, 和部分IP的功能由操作系统提供, 不同的编程语言只是提供了对操作系统的简单封装.
    • 操作系统抽出Socket接口, 每个应用程序对应不同的Socket, 数据包才能正确地发到对应的应用程序
    • socket: ip + 端口号. 小于1024的属于特权端口
    • 使用Socket进行网络编程的本质, 是两个进程之间的网络通信.
      • 一个进程充当服务器, 主动监听某个指定的端口
      • 一个进程充当客户端, 主动链接服务器的ip地址和指定端口
      • 连接成功后, 服务器和客户端成功建立一个TCP连接, 双方后续就可以随时发送和接受数据
    • Socket成功建立后:
      • 服务端socket是指定的ipd地址和指定的端口号
      • 客户端的socket是它所在的计算机的ip地址和一个由操作系统分配的随机端口号.

    案例运行顺序

    1. 启动服务器, 监听端口, 一直查看有没有其他socket访问这个端口的.
    2. 有, 便开启一个新的线程 | 客户端链接这个socket
    3. 获取socket的输入和输出 | 客户端获取socket的输入和输出
    4. 服务器端向socket写入'hello'
    5. 客户端读取socket中数据 [server]: hello
    6. 客户端获取屏幕输入的数据, 并写入socket中
    7. 服务器端接受到socket中数据, 修改后, 再次写入socket中
    8. 客户端收到socket中数据, 并打印在屏幕上: ok: ...

    UDP编程

    • udp编程没有创建连接, 数据包一次收发一个, 没有流的概念
    • udp编程使用socket, 指定ip和端口号. 但是和tcp是两套完全独立的端口.

    HTTP编程

    • 超文本传输协议, 基于HTTP协议之上的一种请求-响应协议.

    • 客户端和服务器端首先建立TCP链接, 服务器总是使用80和安全的443端口

    • 然后客户端向服务器发送一个HTTP请求, 服务器端接受后, 返回一个HTTP响应, 包含HTML数据

    • 客户端解析HTML后展示给用户.

    • HTTP协议是固定的, 由header和body组成

    • Header:

      • 第一行总是: 请求方法 路径 HTTP版本号
      • 后面总是: Header: value格式
      • Host: 表示请求的域名, 因为一台服务器上可能含有多个网站, 因此有必要依靠Host进行区分
      • User-Agent: 客户端自身标识
      • Accept: 表示客户端可以处理的HTTP响应格式
      • Accept-Language: 表示客户端接受的语言.
    • Get请求, 只有header没有body.

    • POST请求通常要设置Content-Type表示body类型. Content-Length表示内容长度.

    • POST请求中代用body, 用一个空行分割

    • GET请求的参数必须放到url上, 有长度限制

    • 响应的第一行总是: HTTP版本 响应代码 响应说明

      • 1**: 提示行响应, eg: 101: 切换协议, 常见WebSocket协议
      • 2**: 表示成功: 200表示成功, 206表示发送了部分内容
      • 3**: 表示重定向: eg: 301表示永久重定向, 303表示客户端应该按照指定路径重新发送请求
      • 4**: 表示因为客户端问题导致的错误
      • 5**: 表示服务器端错误
    • 请求图片的时候, 图片会把二进制内容发送给客户端

    • 服务器总是被动的接受客户端的请求, 并并响应他

    • http1.1允许在一个tcp请求中反复发送-响应

    • http2.0允许同时发送多个请求, 返回的时候, 不一定按照顺序返回

    java的Http编程

    • 只讨论客户端的http编程
    • 早期JDK使用HttpURLConnection进行实现
    URL url = new URL("http://www.baidu.com");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setUseCaches(false);
        conn.setConnectTimeout(5000);
        // 设置http请求头
        conn.setRequestProperty("Accept", "*/*");
        conn.setRequestProperty("User-Agent", "Mozilla/5.0 (compatible; MSIE 11; Windows NT 5.1)");
        // 发送http请求
        conn.connect();
    //    if (conn.getResponseCode() != 200) {
    //      throw new RuntimeException();
    //    }
        // 获取所有的响应
        Map<String, List<String>> map = conn.getHeaderFields();
        for (String key: map.keySet()) {
          System.out.println(key+": "+map.get(key));
        }
        // 获取响应内容
        InputStream input = conn.getInputStream();
    
    public class Client {
      static HttpClient httpClient = HttpClient.newBuilder().build(); // 创建全局实例, 内部使用线程池优化多个http连接
      public static void main(String[] args) throws IOException, URISyntaxException, InterruptedException {
        String url = "https://www.sina.com.cn";
        HttpRequest request = HttpRequest.newBuilder(new URI(url))
            .header("User-Agent",  "Java HttpClient")
            .header("Accept", "*/*")
            .timeout(Duration.ofSeconds(5))
            .version(Version.HTTP_2)
            .build();
        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
        // Http允许重复的header, 因此一个header可对应多个value
        Map<String, List<String>> headers = response.headers().map();
        for(String header: headers.keySet()) {
          System.out.println(header + ": " + headers.get(header).get(0));
        }
        System.out.println(response.body().substring(0, 1024) + "...");
      }
    }
    
    • 获取图片, 使用HttpResponse.BodyHandlers.ofByteArray()进行转换
    • 响应内容很大的时候, 可以使用HttpResponse.BodyHandlers.ofInputStream()获取一个数据流进行加载
    • 使用POST请求, 正确设置Content-type即可

    发送邮件

    • 各个过程:
      • MUA: Mail User Agent
      • MTA: Mail Transfer Agent
      • MDA: Mail Delivery Agent
    • mua给mta发送邮件的协议是SMTP协议 simple mail transfer protocal协议, 使用25端口, 或者加密端口465或587
    • stmp建议在tcp协议之上
    • 一个Multipart可以添加若开个bodypart, 第一个是正文, 后面是附件

    接受邮件

    • 接受邮件使用POP3/IMAP协议

    RMI远程调用

    • 一个jvm可以通过网络实现远程调用另一个jvm的方法
    • remote method invocation
    • 实现RMI服务端和客户端共享一个接口
    • 此接口必定派生自java.rmi.Remote, 并在每个方法中声明RemoteException
    public class Server {
      public static void main(String[] args) throws RemoteException {
        System.out.println("create World clock remote service...");
        // 实例化一个WorldClock:
        WorldClock worldClock = new WorldClockService();
        // 将此服务转换为远程服务接口:
        WorldClock skeleton = (WorldClock) UnicastRemoteObject.exportObject(worldClock, 0);
        // 将RMI端口注册到1099端口
        Registry registry = LocateRegistry.createRegistry(1099);
        // 注册此服务, 服务为"WorldClock"
        registry.rebind("WorldClock", skeleton);
      }
    }
    
    // 客户端调用方法, 通过这个实现类返回结果
    public class WorldClockService implements WorldClock {
      @Override
      public LocalDateTime getLocalDateTime(String zoneId) throws RemoteException{
        return LocalDateTime.now(ZoneId.of(zoneId)).withNano(0);
      }
    }
    
    public interface WorldClock extends Remote {
      LocalDateTime getLocalDateTime(String zoneId) throws RemoteException;
    }
    
    // 客户端只有接口, 并没有实现类, 使用的是服务端实现类获得数据
    public class Client {
      public static void main(String[] args) throws RemoteException, NotBoundException {
        // 连接到服务器, 端口1099
        Registry registry = LocateRegistry.getRegistry("localhost", 1099);
        // 查找服务, 并进行强制转换
        WorldClock worldClock = (WorldClock) registry.lookup("WorldClock");
        // 正常调用接口方法
        LocalDateTime now = worldClock.getLocalDateTime("Asia/Shanghai");
        System.out.println(now);
      }
    }
    
    • 客户端对应的WorldClock对应了一个实现类, 由Registry动态生成, 并把方法调用通过网络传递到服务端.
    • 服务器接受到的网络调用的服务并不是我们自己编写的WorldClockService, 而是Registry自动生成的代码, 我们把客户端的实现类称为stub, 而服务端的网络服务类称为skeleton, 会真正调用worldClockService, 获得结果.
    • rmi严重依赖序列化和反序列化, 这种情况下会造成漏洞, 因此必须是双方信任的内网机器
  • 相关阅读:
    防盗链(三)nginx实现图片防盗链(referer指令)
    防盗链(二)nginx secure_link下载防盗链
    防盗链(一)资料整理
    如何实现 token 加密
    Socket编程(三)demo举例
    Socket编程-(二)tcp三次握手与四次挥手
    Spring的事务控制,注解和xml配置以及解释
    SpringAop的核心概念和使用,表达式匹配刨析,xml配置通知和环绕通知
    SpringAop的简介
    Spring整合JUnit测试单元
  • 原文地址:https://www.cnblogs.com/zhangrunhao/p/13173559.html
Copyright © 2020-2023  润新知