DAY13.1 Java核心基础
TCP协议
TCP 协议是面向连接的运算层协议,比较复杂,应用程序在使用TCP协议之前必须建立连接,才能传输数据,数据传输完毕之后需要释放连接
就好比现实生活中的打电话,首先确保电话打通了才能进行通信,如果没有打通则阻塞,需要等待打通才能对话
TCP优缺点:
- 优点:安全可靠,数据不会丢失,并且数据是按照先后顺序依次到达
- 缺点:速度慢,效率低,常用于对于业务安全要求较高的场景
Java中如何使用 TCP 呢?
java中通过Socket类来建立TCP连接,使用这个类可以在服务端和客户端建立一个可靠的连接
Socket表示客户端,ServerSocket表示服务端
它们都在java.net包中
在服务端创建ServerSocket对象,通过对象的accept()方法可以接收到若干个表示客户端的Socket对象
ServerSocket
方法 | 描述 |
---|---|
public ServerSocket(int port) | 根据端口创建 ServerSocket 实例对象 |
public ServerSocket(int port,int backlog) | 根据端口和 backlog 创建 ServerSocket 对象 |
public ServerSocket(int port,int backlog,InetAddress address) | 根据端口、backlog、IP 创建 ServerSocket对象 |
public ServerSocket() | 创建没有绑定服务器的 ServerSocket 对象 |
public synchronized int getSoTimeout() | 获取 Sotimeout 的设置 |
public InetAddress getInetAddress() | 获取服务器的 IP 地址 |
public Socket accept() | 等待客户端请求,并返回 Socket 对象 |
public void close() | 关闭 ServerSocket |
public boolean isClosed() | 返回 ServerSocket 的关闭状态 |
public void bind(SocketAddress address) | 将 ServerSocket 实例对象绑定到指定地址 |
public int getLocalPort() | 返回 ServerSocket 的端口 |
Socket
方法 | 描述 |
---|---|
public Socket(String host,int port) | 根据主机、端口创建 Socket 对象 |
public Socket(InetAddress host,int port) | 根据 IP、端口创建 Socket 对象 |
public Socket(String host,int port,InetAddress address,int localPort) | 根据主机、端口创建要连接的 Socket 对象并将其连接到指定的远程主机上的指定端口 |
public Socket(InetAddress host,int port,InetAddress address,int localPort) | 根据主机、端口创建要连接的 Socket 对象并将其连接到指定的远程主机上的指定端口 |
pubilc Socket() | 创建没有连接的 Socket 对象 |
public InputStream getInputStream() | 返回 Socket 的输入流 |
public synchronized void close() | 关闭 Socket |
public boolean isClosed() | 返回 Socket 的关闭状态、 |
DataInputStream 的作用
读取基本数据类型:提供方法直接读取二进制数据为Java基本类型,例如:
- int readInt():读取4字节为int。
- double readDouble():读取8字节为double。
- String readUTF():读取修改后的UTF-8编码字符串。
跨平台一致性:数据以**网络字节序(Big-Endian)**存储,确保不同平台间数据读写兼容。
DataOutputStream 的作用
写入基本数据类型:将Java基本类型转换为字节序列写入流中,例如:
- void writeInt(int v):将int写入为4字节。
- void writeDouble(double v):将double写入为8字节。
- void writeUTF(String str):以修改后的UTF-8格式写入字符串。
数据序列化:常用于将数据结构(如对象的字段)转换为字节流,便于存储或网络传输。
服务端启动的时候可以接收多个客户端的信息
服务端:ServerSocket
public class Server {public static void main(String[] args) {ServerSocket serverSocket = null;Socket socket = null;OutputStream outputStream = null;InputStream inputStream = null;DataInputStream dataInputStream = null;DataOutputStream dataOutputStream = null;try {serverSocket = new ServerSocket(8080);System.out.println("------服务端------");System.out.println("已启动,等待接收客户端请求...");while (true){socket = serverSocket.accept();inputStream = socket.getInputStream();dataInputStream = new DataInputStream(inputStream);String request = dataInputStream.readUTF();System.out.println("接收到了客户端请求:" + request);outputStream = socket.getOutputStream();dataOutputStream = new DataOutputStream(outputStream);String response = "Hello World";dataOutputStream.writeUTF(response);System.out.println("给客户端做出响应:" + response);}} catch (Exception e){} finally {try {dataOutputStream.close();outputStream.close();dataInputStream.close();inputStream.close();socket.close();serverSocket.close();} catch (IOException e) {e.printStackTrace();}}}
}
核心就是通过while循环accept()接收客户端的连接,然后通过DataInputStream和DataOutputStream实现了接收和发送的业务
启动等待客户端连接…
客户端:Socket
public class Client {public static void main(String[] args) {Socket socket = null;OutputStream outputStream = null;DataOutputStream dataOutputStream = null;InputStream inputStream = null;DataInputStream dataInputStream = null;try {socket = new Socket("127.0.0.1", 8080);System.out.println("------客户端------");String request = "你好!";System.out.println("客户端说:" + request);outputStream = socket.getOutputStream();dataOutputStream = new DataOutputStream(outputStream);dataOutputStream.writeUTF(request);inputStream = socket.getInputStream();dataInputStream = new DataInputStream(inputStream);String response = dataInputStream.readUTF();System.out.println("服务器的响应是:" + response);} catch (Exception e){} finally {try {inputStream.close();dataInputStream.close();dataOutputStream.close();outputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();}}}
}
客户端接收到的消息:
此时服务端的输出为:
UDP协议
TCP 协议连接可以建立稳定可靠的连接,保证信息的完整性,但是它的缺点也很明显,先建立连接再进行操作的方式效率必然低下
实际开发应用中,有些场景不需要可靠的连接,而是需要效率很高的传输,但连接不可靠,容易数据丢失
TCP:打电话,需要建立连接
UDP(发送消息,不需要建立连接):
- 效率高,速度快,不需要建立连接,直接发送即可
- 连接不可靠,容易数据丢失,安全性不高
DatagramSocket和DatagramPacket
DatagramSocket (邮箱,等待接收消息):
方法 | 描述 |
---|---|
public DatagramSocket(int port) | 根据端口创建 DatagramSocket 实例对象 |
public void send(DatagramPacket p) | 发送数据报 |
public synchronized void receive(DatagramPacket p) | 接收数据报 |
public InetAddress getInetAddress() | 获取 DatagramSocket 对应的 InetAddress 对象 |
public boolean isConnected() | 判断是否连接到服务 |
DatagramPacket(信封:封装发送的消息以及发送的地址):
方法 | 描述 |
---|---|
public DatagramPacket(byte[] buff,int length,InetAddress address,int port) | 根据发送的数据、数据长度、IP、端口创建 DatagramPacket 对象 |
public synchronized byte[] getData() | 获取接收的数据 |
public synchronized int getLength() | 获取数据长度 |
public synchronized int getPort() | 获取发送数据的 Socket 端口 |
public synchronized SocketAddress getSocketAddress() | 获取发送数据的 Socket 信息 |
客户端A:
public class TerminalA {public static void main(String[] args) {// 创建信箱try {byte[] buff= new byte[1024];SocketAddress socketAddress =new InetSocketAddress("127.0.0.1",8081);DatagramPacket datagramPacket= new DatagramPacket(buff,buff.length,socketAddress);DatagramSocket datagramSocket =new DatagramSocket(8080);// 等待接收8081信箱的消息System.out.println("客户端A等待接收消息....");datagramSocket.receive(datagramPacket);// 接收消息String msg = new String(datagramPacket.getData(),0,datagramPacket.getLength());System.out.println("接收到来自"+datagramPacket.getAddress()+":"+datagramPacket.getPort()+"端口的消息:"+msg);// 发送消息String s = "你好我是客户端A";byte[] bytes = s.getBytes();DatagramPacket datagramPacket1 =new DatagramPacket(bytes,bytes.length,new InetSocketAddress("127.0.0.1",8081));datagramSocket.send(datagramPacket1);} catch (IOException e) {throw new RuntimeException(e);}}
}
如果没有消息则一直阻塞等待
阻塞发生在 datagramSocket.receive(datagramPacket);
客户端 B:
public class TerminalB {public static void main(String[] args) {try {// 创建信箱DatagramSocket datagramSocket =new DatagramSocket(8081);// 发送消息给8080String s = "你好我是客户端B";byte[] bytes = s.getBytes();DatagramPacket datagramPacket1 =new DatagramPacket(bytes,bytes.length,new InetSocketAddress("127.0.0.1",8080));datagramSocket.send(datagramPacket1);// 接收消息SocketAddress socketAddress =new InetSocketAddress("127.0.0.1",8080);byte[] buff= new byte[1024];DatagramPacket datagramPacket= new DatagramPacket(buff,buff.length,socketAddress);// 等待接收8080信箱的消息System.out.println("客户端B等待接收消息....");datagramSocket.receive(datagramPacket);String msg = new String(datagramPacket.getData(),0,datagramPacket.getLength());System.out.println("接收到来自"+datagramPacket.getAddress()+":"+datagramPacket.getPort()+"端口的消息:"+msg);} catch (IOException e) {throw new RuntimeException(e);}}
}
发送消息给A,A给B回信