Java ⽹络编程、通信协议、TCP、UDP协议详解
文章目录
一、⽹络编程
概述
常⻅计算机⽹络
- 互联⽹:(Internet)点与点相连。
- 万维⽹:(WWW – World Wide Web)端与端相连。
- 物联⽹:( IoT - Internet of things) 物与物相连。
- ⽹络编程:让计算机与计算机之间建⽴连接、进⾏通信。
⽹络通信协议
通过计算机⽹络可以使多台计算机实现连接,位于同⼀个⽹络中的计算机在进⾏连接和通信时需要遵守⼀定的规则,这就好⽐在道路中⾏驶的汽⻋⼀定要遵守交通规则⼀样。在计算机⽹络中,这些连接和通信的规则被称为⽹络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统⼀规定,通信双⽅必须同时遵守才能完成数据交换。
⽹络模型
OSI参考模型
OSI(Open System Interconnect),即开放式系统互联。
- 是ISO组织在1985年研究的⽹络互联模型。
- 该体系结构标准定义了⽹络互联的七层框架(物理层、数据链路层、⽹络层、传输层、会话层、表示层和应⽤层)。
每层功能: - 第七层:应⽤层负责⽂件访问和管理、可靠运输服务、远程操作服务。(HTTP、FTP、SMTP)。
- 第六层:表示层负责定义转换数据格式及加密,允许选择以⼆进制或ASCII格式传输。
- 第五层:会话层负责使应⽤建⽴和维持会话,使通信在失效时继续恢复通信。(断点续传)。
- 第四层:传输层负责是否选择差错恢复协议、数据流重⽤、错误顺序重排。(TCP、UDP)。
- 第三层:⽹络层负责定义了能够标识所有⽹络节点的逻辑地址。(IP地址)。
- 第⼆层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)。
- 第⼀层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、光导纤维)。
TCP/IP模型
- TCP/IP模型是因特⽹使⽤的参考模型,基于TCP/IP的参考模型将协议分成四个层次。
- 该模型中最重要的两个协议是TCP和IP协议。
上图中,TCP/IP协议中的四层分别是应⽤层、传输层、⽹络层和链路层,每层分别负责不同的通信功能。 - 链路层:链路层是⽤于定义物理传输通道,通常是对某些⽹络连接设备的驱动协议,例如针对光纤、⽹线提供的驱动。
- ⽹络层:⽹络层是整个TCP/IP协议的核⼼,它主要⽤于将传输的数据进⾏分组,将分组数据发送到⽬标计算机或者⽹络。
- 运输层:主要使⽹络程序进⾏通信,在进⾏⽹络通信时,可以采⽤TCP协议,也可以采⽤UDP协议。
- 应⽤层:主要负责应⽤程序的协议,例如HTTP协议、FTP协议等。
UDP和TCP
UDP:
⽤户数据报协议(User Datagram Protocol)。UDP是⽆连接通信协议,即在数据传输时,数据的发送端和接收端不建⽴逻辑连接。简单来说,当⼀台计算机向另外⼀台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
由于使⽤UDP协议消耗资源⼩,通信效率⾼,所以通常都会⽤于⾳频、视频和普通数据的传输例如视频会议都使⽤UDP协议,因为这种情况即使偶尔丢失⼀两个数据包,也不会对接收结果产⽣太⼤影响。
TCP:
传输控制协议 (Transmission Control Protocol)。TCP协议是⾯向连接的通信协议,即传输数据之前,在发送端和接收端建⽴逻辑连接,然后再传输数据,它提供了两台计算机之间可靠⽆差错的数据传输。
在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握⼿”。
三次握⼿:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
- 第⼀次握⼿,客户端向服务器端发出连接请求,等待服务器确认。
- 第⼆次握⼿,服务器端向客户端回送⼀个响应,通知客户端收到了连接请求。
- 第三次握⼿,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。
完成三次握⼿,连接建⽴后,客户端和服务器就可以开始进⾏数据传输了。由于这种⾯向连接的特性,TCP协议可以保证传输数据的安全,所以应⽤⼗分⼴泛,例如下载⽂件、浏览⽹⻚等。
TCP/UDP区别
TCP(传输控制协议,Transmission Control Protocol):(类似打电话)⾯向连接、传输可靠(保证数据正确性)、有序(保证数据顺序)、传输⼤量数据(流模式)、速度慢、对系统资源的要求多,程序结构较复杂,每⼀条TCP连接只能是点到点的,TCP⾸部开销20字节。
UDP(⽤户数据报协议,User Data Protocol):(类似发短信)⾯向⾮连接 、传输不可靠(可能丢包)、⽆序、传输少量数据(数据报模式)、速度快,对系统资源的要求少,程序结构较简单 ,UDP⽀持⼀对⼀,⼀对多,多对⼀和多对多的交互通信,UDP的⾸部开销⼩,只有8个字节。
TCP编程
概述
TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分为客户端(Client)与服务端(Server)。
两端通信时步骤:
- 服务端程序,需要事先启动,等待客户端的连接。
- 客户端主动连接服务器端,连接成功才能通信。服务端不可以主动连接客户端。
TCP创建
在Java中,提供了两个类⽤于实现TCP通信程序:
- 客户端: java.net.Socket 类表示。创建 Socket 对象,向服务端发出连接请求,服务端响应请求,两者建⽴连接开始通信。
- 服务端: java.net.ServerSocket 类表示。创建 ServerSocket 对象,相当于开启⼀个服务,并等待客户端的连接。
开发步骤:
- 建⽴通信连接(会话):
- 创建ServerSocket,指定端⼝号。
- 调⽤accept等待客户端接⼊。
- 客户端请求服务器:
- 创建Socket,指定服务器IP + 端⼝号。
- 使⽤输出流,发送请求数据给服务器。
- 使⽤输⼊流,接收响应数据到客户端(等待)
- 服务器响应客户端。
- 使⽤输⼊流,接收请求数据到服务器(等待)。
- 使⽤输出流,发送响应数据给客户端。
客户端向服务器发送数据
服务端实现:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerTCP {
public static void main(String[] args) throws IOException {
System.out.println("服务端启动 , 等待连接 .... ");
// 1.创建 ServerSocket对象,绑定端⼝,开始等待连接
ServerSocket ss = new ServerSocket(9081);
// 2.接收连接 accept ⽅法, 返回 socket 对象.
Socket server = ss.accept();
// 3.通过socket 获取输⼊流
InputStream is = server.getInputStream();
// 4.⼀次性读取数据
// 4.1 创建字节数组
byte[] b = new byte[1024];
// 4.2 据读取到字节数组中.
int len = is.read(b);
// 4.3 解析数组,打印字符串信息
String msg = new String(b, 0, len);
System.out.println(msg);
//5.关闭资源.
is.close();
server.close();
}
}
客户端实现:
import java.io.OutputStream;
import java.net.Socket;
public class ClientTCP {
public static void main(String[] args) throws Exception {
System.out.println("客户端 发送数据");
// 1.创建 Socket ( ip , port ) , 确定连接到哪⾥.
Socket client = new Socket("localhost", 9081);
// 2.获取流对象 . 输出流
OutputStream os = client.getOutputStream();
// 3.写出数据.
os.write("你好么? tcp ,我来了".getBytes());
// 4. 关闭资源 .
os.close();
client.close();
}
}
服务器向客户端回写数据
服务端实现:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerTCP02 {
public static void main(String[] args) throws IOException, IOException {
System.out.println("服务端启动 , 等待连接 .... ");
// 1.创建 ServerSocket对象,绑定端⼝,开始等待连接
ServerSocket ss = new ServerSocket(9081);
// 2.接收连接 accept ⽅法, 返回 socket 对象.
Socket server = ss.accept();
// 3.通过socket 获取输⼊流
InputStream is = server.getInputStream();
// 4.⼀次性读取数据
// 4.1 创建字节数组
byte[] b = new byte[1024];
// 4.2 据读取到字节数组中.
int len = is.read(b);
// 4.3 解析数组,打印字符串信息
String msg = new String(b, 0, len);
System.out.println(msg);
// =================回写数据=======================
// 5. 通过 socket 获取输出流
OutputStream out = server.getOutputStream();
// 6. 回写数据
out.write("我很好,谢谢你".getBytes());
// 7.关闭资源.
out.close();
is.close();
server.close();
}
}
客户端实现:
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ClientTCP02 {
public static void main(String[] args) throws Exception {
System.out.println("客户端 发送数据");
// 1.创建 Socket ( ip , port ) , 确定连接到哪⾥.
Socket client = new Socket("localhost", 9081);
// 2.通过Scoket,获取输出流对象
OutputStream os = client.getOutputStream();
// 3.写出数据.
os.write("你好么? tcp ,我来了".getBytes());
// ==============解析回写=========================
// 4. 通过Scoket,获取 输⼊流对象
InputStream in = client.getInputStream();
// 5. 读取数据数据
byte[] b = new byte[100];
int len = in.read(b);
System.out.println(new String(b, 0, len));
// 6. 关闭资源 .
in.close();
os.close();
client.close();
}
}
案例:简易聊天
服务端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TCPServer_IM {
public static void main(String[] args) {
System.out.println("服务端启动。。。");
Socket server = null;
InputStream is = null;
OutputStream os = null;
//1,创建SocketServer对象,绑定端⼝,等待连接
try {
ServerSocket serverSocket = new ServerSocket(8888);
Scanner sc = new Scanner(System.in);
server = serverSocket.accept();
while (true) {
//3,通过Socket获取输⼊流
is = server.getInputStream();
//4,读取数据
byte[] buff = new byte[1024];
int len = is.read(buff);
String msg = new String(buff, 0, len);
System.out.println("客户端:" + msg);
//5,服务端回写数据
os = server.getOutputStream();
System.out.print("请输⼊服务端信息:");
String serverMsg = sc.nextLine();
os.write(serverMsg.getBytes());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (is != null) {
is.close();
}
if (server != null) {
server.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class TCPClient_IM {
public static void main(String[] args) {
System.out.println("客户端启动。。。。");
Scanner sc = new Scanner(System.in);
Socket client = null;
OutputStream os = null;
InputStream is = null;
try {
//1,创建Socket对象,连接到指定的服务端
client = new Socket("localhost", 8888);
while (true) {
//2,通过socket对象获取输出流,给服务端发送消息
os = client.getOutputStream();
System.out.print("请录⼊客户端的消息:");
String input = sc.nextLine();
os.write((input).getBytes());
//3,获取服务器发送的消息
is = client.getInputStream();
//4,读取数据
byte[] buff = new byte[1024];
int len = is.read(buff);
String msg = new String(buff, 0, len);
System.out.println("服务端:" + msg);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
if (os != null) {
os.close();
}
if (client != null) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}