Java网络编程

111 阅读3分钟

Java中的网络编程都依赖所谓的套接字来完成,表示套接字的对象是Socket对象。它的作用在于开启与外部的相互通信。

使用Socket搭建一个服务器

@Test
public void serveTest() throws IOException, InterruptedException {
    ServerSocket serverSocket = new ServerSocket(8888);
    Socket accept = serverSocket.accept();
    accept.getOutputStream().write("hello".getBytes(StandardCharsets.UTF_8));
}

使用Sokcet连接到服务器

@Test
public void test() throws IOException {
    try (Socket s = new Socket("127.0.0.1",8888);
         Scanner sc = new Scanner(s.getInputStream(),StandardCharsets.UTF_8)){
        while (sc.hasNextLine()) {
            System.out.println(sc.nextLine());
        }
    }
}

运行之,请求端输出 hello

上面的示例是Socket最简单的使用说明,其实服务器程序的整个执行过程就是:

  1. 创建一个服务器连接,等待客户端请求。
  2. 接收客户端请求的字节数据,或转为字符去操作;拿到想要的数据信息。
  3. 返回给客户端信息

如果再给上面的步骤套上一层循环,就构成了一个小型的服务器。

@Test
public void serveTest() throws IOException, InterruptedException {
    ServerSocket serverSocket = new ServerSocket(8888);
    Socket accept = serverSocket.accept();
    Scanner scanner = new Scanner(accept.getInputStream(), StandardCharsets.UTF_8);
    while (scanner.hasNextLine()) {
        System.out.println(scanner.nextLine());
    }
}

启动上面的程序可以开启一个服务器,然后打开终端使用telnet命令连接它。
向服务器发送信息:

截屏2023-05-25 16.58.24.png

输出:
hello world
luck day

可中断套接字

当创建一个Socket套接字请求连接资源时,当前的这个线程会一直阻塞到成功建立连接或超时,并且这个阻塞无法人为的中断。这个时候就需要使用可中断的套接字SocketChannel

SocketChannel channe = SocketChannel.open(new InetSocketAddress("127.0.0.1",8888))

它与Socket的区别在于,它有一个缓冲区,所以可以接收一个用户操作比如ButtonActionLinsener,然后使用interrupt来取消不会有结果的线程。而Socket在阻塞时无法调用interrupt,它只是一直等待服务器响应。

HttpClient

HttpClient是功能强大的HTTP客户端。主要用来发出请求和接收响应

HttpClient请求
HttpRequest request = HttpRequest.newBuilder().uri(new URI("http://127.0.0.1:8081")).GET().build();
HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());

代码解读:

HttpRequest request = HttpRequest.newBuilder().uri(newURI("http://127.0.0.1:8081")).GET().build(); 第一行中,newBuilder()表示一个http请求构建器;uri()方法为当前请求设置请求地址;GET()方法表示这是一个get请求;build()方法指以前面的配置构建一个HttpRequest()对象。

HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build(); 第二行中,newBuilder表示新建一个http客户端;followRedirects(...)方法用来指定重定向策略;build()指通过前面的配置构建一个HttpClient对象。

client.send(request, HttpResponse.BodyHandlers.ofString()); 第三行send()方法发送一个同步的请求。第一个参数requestHttpRequest请求;第二个参数的作用则是用来处理Http服务器响应的数据,它是一个处理器,专门用来处理响应体,示例中的处理器将响应数据处理为文本。

Post请求
String json = "{"name":"张三","age":20}";
HttpRequest request = HttpRequest.newBuilder()
        .uri(new URI("http://127.0.0.1:8081")).POST(HttpRequest.BodyPublishers.ofString(json)).build();
HttpClient client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.ALWAYS).build();
HttpResponse<String> response = client.send(request,HttpResponse.BodyHandlers.ofString());
int status = response.statusCode();
System.out.printf("status:%d\nbody:%s",status,response.body());

post请求与get请求的区别在于要为请求配置传入一个报文发布器BodyPublisher,发布器的种类有很多,需要根据要发送的数据类型指定一个恰当的发布器,比如,如果要发送字符串就使用HttpResponse.BodyHandlers.ofString();发送字节数组就使用HttpResponse.BodyHandlers.ofByteArray();甚至还有传递文件的发布器HttpResponse.BodyHandlers.ofFile()