Socket = IP 地址 + 端口号
Socket 是网络上运行的程序之间双向通信链路的终结点,是 TCP 和 UDP 的基础。
- ftp:
21 - telent:
23 - http:
80 - ...
针对网络通信的不同层次, Java 提供的网络功能的四大类:
InetAddress:用于标识网络上的硬件资源URL:统一资源定位符,通过 URL 可以直接读取或写入网络上的资源Socket:使用 TCP 协议实现网络通信的 Socket 相关的类Datagram:使用 UDP 协议,数据保存数据报中,通过网络进行通信
InetAddress address = InetAddress.getLocalHost(); System.out.println(address.getHostName()); System.out.println(address.getHostAddress()); System.out.println(Arrays.toString(address.getAddress())); System.out.println(address);
try { URL url = new URL("https://www.baidu.com"); InputStream is = url.openStream(); InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(isr); String data = br.readLine(); while (data != null) { System.out.println(data); data = br.readLine(); } br.close(); isr.close(); is.close(); } catch (IOException e) { e.printStackTrace(); }
TCP 协议(传输控制协议)是面向连接、可靠的、有序的、以字节流发送数据。
Java 中基于 TCP 协议实现网络通信的类
- 客户端的
Socket类 - 服务端的
ServerSocket类
Socket 通信实现步骤
- 创建
ServerSocket和Socket - 打开连接到
Socket的输入/输出流 - 按照协议对
Socket进行读写操作 - 关闭输入/输出流,关闭
Socket
- 创建
ServerSocket对象,绑定监听端口 - 通过
accept()方法监听客户端请求 - 连接建立后,通过输入流读取客户端发送的请求信息
- 通过输出流向客户端发送响应信息
- 关闭相应资源
// 1. 创建 ServerSocket 对象,绑定监听端口 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("***服务器已经启动,开始侦听客户端的连接***"); // 2. 通过 accept() 方法监听客户端请求 Socket socket = serverSocket.accept(); // 3. 连接建立后,通过输入流读取客户端发送的请求信息 InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String info = null; while ((info = br.readLine()) != null) { System.out.println("我是服务器,客户端说:" + info); } socket.shutdownInput(); // 关闭输入流 // 4. 通过输出流向客户端发送响应信息 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("欢迎你"); pw.flush(); // 5. 关闭相应资源 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close(); serverSocket.close();
- 创建
Socket对象,指明需要连接的服务的地址和端口号 - 连接建立后,通过输出流向服务发送请求信息
- 通过输入流获取服务响应的信息
- 关闭相应资源
// 1. 创建 Socket 对象,指明需要连接的服务器的地址和端口号 Socket socket = new Socket("127.0.0.1", 8888); // 2. 连接建立后,通过输出流向服务器发送请求信息 OutputStream os = socket.getOutputStream(); PrintWriter pw = new PrintWriter(os); pw.write("user:zhangsan;passwd:123456"); pw.flush(); socket.shutdownOutput(); // 关闭输出流 // 3. 通过输入流获取服务器响应的信息 InputStream is = socket.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String resp = null; while ((resp = br.readLine()) != null) { System.out.println("我是客户端,服务器说:" + resp); } socket.shutdownInput(); // 关闭输入流 // 4. 关闭相应资源 pw.close(); os.close(); br.close(); isr.close(); is.close(); socket.close();
- 服务端创建
ServerSocket,循环调用accept()等待客户端连接 - 客户端创建一个
Socket并请求和服务端连接 - 服务端接受客户端请求,创建
Socket与该客户端建立专线连接 - 建立连接的两个
Socket在一个单独的 x 线程上对话 - 服务端继续等待新的连接
// 1. 创建 ServerSocket 对象,绑定监听端口 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("***服务器已经启动,开始侦听客户端的连接***"); int count = 0; // 2. 通过 accept() 方法监听客户端请求 Socket socket; while (true) { socket = serverSocket.accept(); ServerThread thread = new ServerThread(socket); thread.setPriority(4); thread.start(); count++; System.out.println("客户端的数量为:" + count); InetAddress address = socket.getInetAddress(); System.out.println("当前客户端的地址为:" + address.getHostAddress()); }
UDP 协议(用户数据报协议)是无连接、不可靠的、无序的。
UDP 协议传输速度快。
UDP 协议以数据报作为数据传输的载体。
使用 UDP 协议进行数据传输时,
-
首先需要将要传输的数据定义成数据报(Datagram)
-
在数据报中指明数据所要达到的 Socket(主机和端口号)
-
然后再将数据报发送出去
-
DatagramPacket:数据报包 -
DatagramSocket:进行端到端通信的类
- 创建
DatagramSocket,指定端口号 - 创建
DatagramPacket - 接受客户端发送的数据信息
- 读取数据
// 1. 创建 DatagramSocket,指定端口号 DatagramSocket socket = new DatagramSocket(8888); // 2. 创建 DatagramPacket byte[] data = new byte[1024]; DatagramPacket packet = new DatagramPacket(data, data.length); System.out.println("***服务器已经启动,开始侦听客户端的连接***"); // 3. 接受客户端发送的数据信息 // 此方法在接收到数据之前按一直会保持阻塞 socket.receive(packet); // 4. 读取数据 String info = new String(data, 0, packet.getLength()); System.out.println("我是服务器,客户端说:" + info); // 服务器向客户端进行响应 InetAddress address = packet.getAddress(); int port = packet.getPort(); byte[] resp = "你好,这是服务器对客户端的响应".getBytes(); DatagramPacket respPacket = new DatagramPacket(resp, resp.length, address, port); socket.send(respPacket); socket.close();
- 定义发送信息
- 创建
DatagramPacket,包含所要发送的信息 - 创建
DatagramSocket - 发送数据
// 1. 定义发送信息 InetAddress address = InetAddress.getLocalHost(); int port = 8888; byte[] data = "user:zhangsan;passwd:888888".getBytes(); // 2. 创建 DatagramPacket,包含所要发送的信息 DatagramPacket packet = new DatagramPacket(data, data.length, address, port); // 3. 创建 DatagramSocket DatagramSocket socket = new DatagramSocket(); // 4. 发送数据 socket.send(packet); // 客户端接收服务器端的响应 byte[] resp = new byte[1024]; DatagramPacket respPacket = new DatagramPacket(resp, resp.length); socket.receive(respPacket); String info = new String(resp, 0, respPacket.getLength()); System.out.println("我是客户端,服务器响应的信息为:" + info);
- 线程优先级
- 对于同一个
Socket- 如果关闭了输出流,则与该输出流关联的
Socket也会被关闭 - 所以一般不需要关闭流,直接关闭
Socket即可
- 如果关闭了输出流,则与该输出流关联的
- TCP 传输字符串、对象
Socket传递文件