InetAddress

InetAddress 类用于封装 IP 地址或者域名,支持 IPv4 和 IPv6。

创建 InetAddress 对象需要使用工厂方法,因为没有提供显式构造器。工厂方法如下

static InetAddress getLocalhost();
static InetAddress getByName(String hostName);
// 一个域名对应多个 IP 地址时,返回这些地址构造的 InetAddress 对象
static InetAddress[] getAllByName(String hostName);
public static void main(String[] args) throws UnknownHostException {
    // 主机 ip 地址
    // InetAddress 输出格式:主机名称/ip地址
    InetAddress localHost = InetAddress.getLocalHost();
    System.out.println(localHost);

    // 域名 id 地址
    InetAddress bing = InetAddress.getByName("cn.bing.com");
    System.out.println(bing);

    // 域名对应的多个 ip 地址
    InetAddress[] bings = InetAddress.getAllByName("cn.bing.com");
    for( InetAddress e : bings) {
        System.out.println(e);
    }
}

getByAddress() 方法接收一个 IP 地址,返回一个 InetAddress 对象。

InetAddress 类有两个子类 Inet4AddressInet6Address,分别表示 IPv4 和 IPv6 地址。

TCP/IP 客户端 Sockets

socket 用于连接 I/O 系统和其他程序。

ServerSocket 类用于服务器,作为“监听器”,等待客户端的请求。Socket 类用于客户端,用于连接服务器 socket 和发起协议交换过程。

Socket 对象的创建隐式建立了客户端和服务器的连接。该对象的方法可以获取服务器的地址、端口号等信息。

Socket(String hostName, int port);
Socket(InetAddress ipAddress, int port);

getInputStream()getOutputStream() 方法用于获取和 Socket 关联的输入流、输出流。

InputStream getInputStream();
OutputStream getOutputStream();

关闭 socket 时,与它关联的 I/O 流也会关闭。

public static void m() {
  try (var s = new Socket("xx.xxx.com", 80)) {
    var in = s.getInputStream();
    var out = s.getOutputStream();
    byte[] buf = "send information".getBytes();
    // 发送
    out.write(buf);
    int c;
    // 读取响应
    while ((c = in.read()) != -1) {
      System.out.println((char)c);
    }
  }
}

URL

统一资源定位符(Uniform Resource Locator,URL)唯一标识网络中某个资源的地址。

URL 由 4 部分构成,第一个部分是使用的协议;第二个部分是主机名或 IP 地址;第三个部分是端口号,可选;第四个部分是文件的实际路径。

常用构造器如下

URL(String urlSpecifier);
URL(String protocol, String host, int port, String path);
URL(String protocol, String host, String path);
URL(URL url, String urlSpecifier);
public static void main(String[] args) throws MalformedURLException {
    URL url = new URL("https://cn.bing.com");
    System.out.println(url.getHost());
    // 没有指定端口时返回 -1
    System.out.println(url.getPort());
}

为了获取 URL 对象表示的信息,需要调用 openConnection() 方法获取 URLConnection 对象。

URL Connection

URLConnection 类用于访问远程资源属性。这些属性由 HTTP 协议指定。URLConnection 对象的方法主要用于获取 HTTP 头属性,比如 getHeaderFields() 方法返回所有 HTTP 头属性,由 map 存储。

public static void main(String[] args) throws Exception {
    URL url = new URL("http://www.internic.net");
    URLConnection urlC = url.openConnection();
    System.out.println(urlC.getContentType());
    System.out.println(urlC.getContentEncoding());
}

HttpURLConnection

HttpURLConnection 类是 URLConnection 的子类,用于 HTTP 连接。调用 openConnection() 方法然后将返回结果显示转换成 HttpURLConnection 类得到 HttpURLConnection 对象。需保证打开的连接是 HTTP 连接。

public static void m() {
  var u = new URL("http://xxx.xx.com");
  var huc = (HttpURLConnection)u.openConnection();
  Map<String, List<String>> header = huc.getHeaderFields();
  Set<String> keys = header.keySet();
  for (String k : keys) {
    System.out.println(k + " : " + header.get(k));
  }
}

URI 类封装了统一资源标识符(Uniform Resource Identifier,URI)。URI 是表示资源的标准方式,URL 是它的子集。

TCP/IP Server Sockets

ServerSocket 对象用于监听是否有本地或者远程的程序连接自己发布的端口。

ServerSocket 的构造器可以指定队列长度。默认是 50。表示当请求的数量小于等于该队列容量时可以得到处理,大于时,后到达的拒绝连接。构造器如下

// 指定监听的端口号
ServerSocket(int port);
ServerSocket(int port, int maxQueue);
// 允许时,该对象与指定地址绑定
ServerSocket(int port, int maxQueue, InetAddress localAddress);

accept() 调用后等待客户端发起通信,当接收到请求时,返回一个 Socket 用于和客户端通信。

Datagrams

数据报(Datagrams)是机器之间传输的一组信息,它发送之后,不保证目标方能否收到,收到的数据报是否正确。Java 在 UDP 协议上层实现了数据报,使用两个类:DatagramPacket 和 DatagramSocket。其中,DatagramPacket 是数据容器,DatagramSocket 提供了发送和接收 DatagramPacket 对象的机制。

DatagramSocket 类的构造器如下

// 和本机上任意一个未使用的端口号绑定
DatagramSocket();
DatagramSocket(int port);
DatagramSocket(int port, InetAddress ipAddress);
DatagramSocket(SocketAddress address);

SocketAddress 是抽象类,InetSocketAddress 是它的实现类,InetSocketAddress 类封装了 IP 地址和端口号。

两个重要方法如下

void send(DatagramPacket packet);
void receive(DatagramPacket packet);

send() 方法将分组 packet 发送到指定端口,receive() 方法等待接收分组。

DatagramPacket 类定义的构造器如下

// 指定接收数据的缓冲区和分组大小
DatagramPacket(byte[] data, int size);
// offset 指定数据在缓冲区开始存储的索引位置
DatagramPacket(byte[] data, int offset, int size);
// 指定接收方的 ip 地址和端口号
DatagramPacket(byte[] data, int size, InetAddress ipAddress, int port);
// 从 data 的 offset 索引位置开始传输数据
DatagramPacket(byte[] data, int offset, int size, InetAddress ip, int port);
class Demo {
  public static int sPort = ;
  public static int cPort = ;
  public static int bSize = 1024;
  public static byte[] buf = new byte[bSize];
  public static DatagramSocket ds;
  
  public static void server() {
    int pos = 0;
    while (true) {
      int c = System.in.read();
      switch(c) {
        case -1:
          System.out.println("quit");
          ds.close();
          break;
        case '\r':
          break;
        case '\n':
          ds.send(new DatagramPacket(buf, pos, InetAddress.getLocalHost(), cPort));
          pos = 0;
          break;
        default:
          buf[pos++] = (byte)c;
      }
    }
  }
  
  public static void client() {
    while (true) {
      var p = new DatagramPacket(buf, buf.length);
      ds.receive(p);
      System.out.println(new String(p.getData(), 0, p.getLength()));
    }
  }
  
  public static void main(String[] args) {
    if (args.length == 1) {
      ds = new DatagramSocket(sPort);
      server();
    } else {
      ds = new DatagramSocket(cPort);
      clien();
    }
  }
}

java.net.http

JDK11 引入了 java.net.http 包,这些新加入的 API 称为 HTTP 客户端 API。支持异步通信 、HTTP/2、流控制(flow control)、双向通信的 WebSocket 协议。

有 3 个核心的 HTTP 客户端 API,HttpClient 封装了 HTTP 客户端,提供发送请求和接收响应的方法;HttpRequest 封装了请求;HttpResponse 封装了响应。三者共同支持 HTTP 的请求和响应特性。

首先,创建 HttpClient 和 HttpRequest ,然后调用 HttpClient 的 send 方法发送 HttpRequest ,该方法返回响应,可以从响应中获取响应头和响应体。

HttpClient 封装了 HTTP 请求/响应机制,支持同步和异步通信。可以使用它发送请求和接收响应。

HttpClient 是一个抽象类,只能使用工厂方法获得实例。它的静态方法 newBuilder() 返回一个 HttpClient 建造者(builder),该建造者实现了 HttpClient.Builder 接口,这个接口提供了若干个用于配置 HttpClient 的方法。建造者调用 build() 方法创建并返回 HttpClient 实例。

// 使用默认配置创建 HttpClient 实例
HttpClient  hc = HttpClient.newBuilder().build();

HttpClient.Builder 接口定义的 followRedirects() 方法用于设置重定向,默认情况下不允许重定向。该方法的参数必须为 HttpClient.Redirect 枚举类型的值:ALWAYS、NEVER 和 NORMAL。NORMAL 表示允许重定向,除非从 https 站点重定向到 http 站点。

HttpClient.Builder b =
  HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL);
HttpClient hc = b.build();

HttpClient 的静态方法 newHttpClient() 返回默认配置的 HttpClient 实例。

var hc = HttpClient.newHttpClient();

HttpClient 对象调用 send() 方法可以发送一个同步请求。

<T> HttpResponse<T> send(HttpRequest req, HttpResponse.BodyHandler<T> handler);

handler 表示如何处理返回的响应。

HttpRequest 抽象类封装了请求,HttpRequest 对象需要使用建造者创建。newBuilder() 方法返回建造者。

// 创建默认建造者
static HttpRequest.Builder newBuilder();
static HttpRequest.Builder newBuilder(URI uri);

HttpRequest.Builder 提供了若干方法用于设置请求,默认的请求方式是 GET。HttpRequest 对象的 method() 返回请求方式的字符串表示,建造者实例调用 build() 方法创建 HttpRequest 实例。

HttpResponse 接口的实现类封装了响应。

HttpResponse<T>

T 指定了体的类型。

请求发送后,会返回一个 HttpResponse 对象,有若干个方法用于访问响应信息。其中,body() 方法返回对体的引用,引用的类型由 send() 方法中 handler 指定。

T body()

int statusCode() 方法返回状态码;HttpHeaders headers() 方法返回响应头。HttpHeaders 类的 map() 方法以键值对的方式返回所有的响应头信息。

Map<String, List<String>> map()

HttpResponse.BodyHandler 接口的实现类处理响应,HttpResponse.BodyHandlers 类预定义了若干体处理工厂方法。

// 将响应体写入 fileName 指定的文件中,HttpResponse.body() 返回该文件的 Path 对象
static HttpResponse.BodyHandler<Path> ofFile(Path fileName);
// 将响应体和输入流绑定,HttpResponse.body() 返回该输入流的引用
static HttpResponse.BodyHandler<InputStream> ofInputStream();
// 将响应体转换成字符串,HttpResponse.body() 返回该字符串
static HttpResponse.BodyHandler<String> ofString();

使用 ofInputStream() 方法时,需要将流完全读取。

class N {
	public static void main(String[] args) {
    var hc = HttpClient.newHttpClient();
    var hq = HttpRequest.newBuilder(new URI("http://www.xxx.com/")).build();
    HttpResponse<InputStream> hr =
	  hc.send(hq, HttpResponse.BodyHandlers.ofInputStream());
    // 请求方法
    hq.method();
    // 响应状态码
    hr.statusCode();
    InputStream input = hr.body();
    int c;
    while ((c = input.read()) != -1) {
      System.out.println((char)c);
    }
  }
}

参考

[1] Herbert Schildt, Java The Complete Reference 11th, 2019.

 posted on 2024-04-24 14:42  x-yun  阅读(3)  评论(0编辑  收藏  举报