TCP编程
通过Socket技术(它是计算机之间进行通信的一种约定或一种方式),我们就可以实现两台计算机之间的通信,Socket也被翻译为套接字,是操作系统底层提供的一项通信技术,它支持TCP和UDP。而Java就对socket底层支持进行了一套完整的封装,我们可以通过Java来实现Socket通信
使用Java进行TCP编程时,需要使用Socket模型
- 服务器端用ServerSocket监听指定端口
- 客户端使用Socket(InetAddress, port)连接服务器
- 服务器端用accept()接收连接并返回Socket
- 双方通过Socket打开InputStream/OutputStream读写数据
- 服务器端通常使用多线程同时处理多个客户端连接,利用线程池可大幅提升效率
- flush()用于强制输出缓冲区到网络
TCP案例
Socket双向通信:服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class ServiceMain { public static void main(String[] args) throws IOException { InputStreamReader isr; BufferedReader br; OutputStreamWriter osw; BufferedWriter bw; String str; Scanner in = new Scanner(System.in); try { ServerSocket server = new ServerSocket(4444); Socket socket = server.accept(); System.out.println(socket.getInetAddress()); System.out.println("建立了一个连接!"); while (true) { isr = new InputStreamReader(socket.getInputStream()); br = new BufferedReader(isr); System.out.println(socket.getInetAddress() + ":" + br.readLine()); osw = new OutputStreamWriter(socket.getOutputStream()); bw = new BufferedWriter(osw); System.out.print("回复:"); str = in.nextLine(); bw.write(str + "\n"); bw.flush(); } } catch (IOException e) { System.out.println("连接异常!"); } } }
|
Socket双向通信:客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package socket; import java.io.*; import java.net.Socket; import java.util.Scanner; public class ServerMain { public static void main(String[] args) throws IOException { InputStreamReader isr; BufferedReader br; OutputStreamWriter osw; BufferedWriter bw; String str; Scanner in = new Scanner(System.in); try { Socket socket = new Socket("localhost", 4444); System.out.println("成功连接服务器"); while (true) { osw = new OutputStreamWriter(socket.getOutputStream()); bw = new BufferedWriter(osw); System.out.print("回复:"); str = in.nextLine(); bw.write(str + "\n"); bw.flush(); isr = new InputStreamReader(socket.getInputStream()); br = new BufferedReader(isr); System.out.println(socket.getInetAddress() + ":" + br.readLine()); } } catch (IOException e) { System.out.println("连接异常!"); } } }
|
UDP编程
在Java中使用UDP编程,仍然需要使用Socket,因为应用程序在使用UDP时必须指定网络接口(IP)和端口号。注意:UDP端口和TCP端口虽然都使用0~65535,但他们是两套独立的端口,即一个应用程序用TCP占用了端口1234,不影响另一个应用程序用UDP占用端口1234
使用UDP协议通信时,服务器和客户端双方无需建立连接:
- 服务器端用DatagramSocket(port)监听端口
- 客户端使用DatagramSocket.connect()指定远程地址和端口
- 双方通过receive()和send()读写数据
- DatagramSocket没有IO流接口,数据被直接写入byte[]缓冲区
UDP编程
UDP发送接收实例:服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import java.io.IOException; import java.net.*; import java.nio.charset.StandardCharsets;
public class UdpService { public static void main(String[] args) throws IOException { try { DatagramSocket server = new DatagramSocket(5060); DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); server.receive(packet); String info = new String(packet.getData(), packet.getOffset(), packet.getLength(), StandardCharsets.UTF_8); System.out.println(packet.getAddress().getHostName() + "(" + packet.getPort() + "):" + info); packet.setData("Hello Client".getBytes()); packet.setPort(5070); packet.setAddress(InetAddress.getLocalHost()); server.send(packet); server.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
UDP发送接收实例:客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.io.IOException; import java.net.*; import java.nio.charset.StandardCharsets;
public class UdpServer { public static void main(String[] args) throws IOException { try { DatagramSocket client = new DatagramSocket(5070); DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); packet.setPort(5060); packet.setAddress(InetAddress.getLocalHost()); packet.setData("Hello Server".getBytes()); client.send(packet); client.receive(packet); String info = new String(packet.getData(), packet.getOffset(), packet.getLength(), StandardCharsets.UTF_8); System.out.println(packet.getAddress().getHostName() + "(" + packet.getPort() + "):" + info); client.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
HTTP编程
浏览器访问Socket服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import java.io.IOException; import java.net.*; import java.nio.charset.StandardCharsets;
public class UdpServer { public static void main(String[] args) throws IOException { try { DatagramSocket client = new DatagramSocket(5070); DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); packet.setPort(5060); packet.setAddress(InetAddress.getLocalHost()); packet.setData("Hello Server".getBytes()); client.send(packet); client.receive(packet); String info = new String(packet.getData(), packet.getOffset(), packet.getLength(), StandardCharsets.UTF_8); System.out.println(packet.getAddress().getHostName() + "(" + packet.getPort() + "):" + info); client.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
HTTP客户端编程
HTTP响应代码
- 1xx:表示一个提示性响应,例如101表示将切换协议,常见于WebSocket连接
- 2xx:表示一个成功的响应,例如200表示成功,206表示只发送了部分内容
- 3xx:表示一个重定向的响应,例如301表示永久重定向,303表示客户端应该按指定路径重新发送请求
- 4xx:表示一个因为客户端问题导致的错误响应,例如400表示因为Content-Type等各种原因导致的无效请求,404表示指定的路径不存在
- 5xx:表示一个因为服务器问题导致的错误响应,例如500表示服务器内部故障,503表示服务器暂时无法响应
从Java 11开始,引入了新的HttpClient,它使用链式调用的API,能大大简化HTTP的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.util.List; import java.util.Map;
public class HttpDemo { static HttpClient httpClient = HttpClient.newBuilder().build();
public static void main(String[] args) throws Exception { String url = "https://www.baidu.com/"; HttpRequest request = HttpRequest.newBuilder(new URI(url)) .header("User-Agent", "Java HttpClient").header("Accept", "*/*") .timeout(Duration.ofSeconds(5)) .version(HttpClient.Version.HTTP_2).build(); HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); 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) + "..."); } }
|