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最简单的使用说明,其实服务器程序的整个执行过程就是:
- 创建一个服务器连接,等待客户端请求。
- 接收客户端请求的字节数据,或转为字符去操作;拿到想要的数据信息。
- 返回给客户端信息
如果再给上面的步骤套上一层循环,就构成了一个小型的服务器。
@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命令连接它。
向服务器发送信息:
输出:
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()方法发送一个同步的请求。第一个参数request指HttpRequest请求;第二个参数的作用则是用来处理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()。