目录
- TCP
- 面向连接的TCP
- 1.TCP概念
- 2.TCP特点
- 3.TCP报文段格式
- 3.TCP连接管理
- TCP编程
- 模拟实现
- UDP
- 无连接的UDP
- 1.UDP概念:用户数据报协议(UDP,User Datagram Protocol)是无连接、不可靠的数据报协议
- 2.UDP特点:
- 3.UDP报文段结构
- UDP编程
- 模拟实现
TCP
面向连接的TCP
1.TCP概念
- 传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议
2.TCP特点
- 面向连接的传输层协议,使用前必须先建立TCP连接,传输后释放TCP连接
- 通信连接维护是面向通信的两个端点的,而不考虑中间网段和节点
- 可靠通信方式,通过TCP连接传送的数据,无差错、不丢失、不重复,并且按序到达
- 面向字节流(InputStream/OutputStream)
- 提供全双工通信,允许通信双方任何时候都能发送数据,两端都设有发送缓存和接受缓存,用来临时存放双向通信的数据
3.TCP报文段格式
3.TCP连接管理
- 三次握手建立连接
- (1)第一次握手:客户端向服务器端发送TCP连接请求数据包,其中包含客户端的初始序列号seq(A)=x。其中报文中同步标志位SYN=1,ACK=0,表示这是一个TCP连接请求数据包文;序号seq=x,表明传输数据时的第一个数据字节的序号是x
(2)第二次握手:服务器收到请求后,会发送连接确认数据包。其中确认报文段,标识位SYN=1,ACK=1,表示这是一个TCP连接响应数据报文,并含服务器的初始序列号seq(B)=y,以及服务器对客户端初始序列号的确认号ack(B) = seq(A) + 1 = x + 1
(3)第三次握手:客户端收到服务器的确认报文后,还需要做出确认,即发送一个序列号seq(A) = x + 1;确认号为ack(A) = y + 1 的报文 - 四次挥手关闭连接
- (1)第一次挥手:关闭客户端到服务器的连接,首先客户端发送一个FIN,用来关闭客户端到服务器的数据传送,然后等待服务器的确认。其中,标志位FIN=1,序列号seq=u
(2)第二次挥手:服务器收到FIN,它发给客户端一个ACK,确认号ack = u + 1
(3)第三次挥手:关闭服务器到客户端的连接,发送一个FIN给客户端,序列号seq=w,确认号ack=u+1
(4)第四次挥手:客户端收到FIN后,并发回一个ACK报文确认,序列号seq=u+1,确认号ack=w+1
TCP拆除连接为什么要等待2MSL呢?
主要目的是防止最后一个ACK包对方没有收到,那么对方在超时后将重发第三次挥手的FIN包,主动关闭端接收到重发的FIN包后可以再发一个ACK包,
- MSL(Maximum Segment Lifetime):最大报文生存时间,它是任何报文在网络上存在的最长时间,超过这个时间将被丢弃
TCP编程
模拟实现
- 多个客户端和服务器端(多线程)通信
- 客户端
public class MyTcpClient {
public static void main(String[] args) {
Socket socket = null;
BufferedReader input;
PrintWriter output = null;
BufferedReader reader = null;
try {
//构造Socket
socket = new Socket("127.0.0.1", 3333);
System.out.println("客户端已经启动...");
while(true){
//发送数据到服务器端
//获取控制台的输入流
input = new BufferedReader(new InputStreamReader(System.in));
String info = input.readLine();
//获取连接对象的输出流
output = new PrintWriter(socket.getOutputStream());
System.out.println("debug-info: "+info);
//输出流对象写入info数据
output.println(info); //tcp存在缓冲区,有可能缓冲区没有刷新就导致数据无法传输
output.flush();
//输出服务器端返回的数据
//获取连接对象的输入流
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String strs = reader.readLine();
System.out.println("客户端显示-->服务器端响应的数据:"+strs);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close();
reader.close();
output.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 服务器端
public class MyTcpServer {
//通信线程
static class SocketHandler extends Thread{
protected Socket socket;
public SocketHandler(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader reader = null;
OutputStream outputStream = null;
BufferedReader input;
//通信
try {
while (true) {
//获取客户端的输入信息
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String strs = reader.readLine();
System.out.println("服务端显示-->接收客户端" + socket.getRemoteSocketAddress() + "的数据:" + strs);
//给客户端发送消息
//获取控制台的输入流
input = new BufferedReader(new InputStreamReader(System.in));
String info = input.readLine();
//获取连接对象的输出流
outputStream = socket.getOutputStream();
outputStream.write(("response: " + info + "\n").getBytes());
//结束通信
if ("".equals(strs) || "exit".equals(strs)) {
System.out.println("通信结束");
break;
}
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
reader.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//主线程
public static void main(String[] args) {
ServerSocket serverSocket = null;
try {
//构造ServerSocket对象 监听port:3333
serverSocket = new ServerSocket(3333);
System.out.println("服务器端已经启动...");
while(true){
//进行监听,等待多个客户端连接
Socket accept = serverSocket.accept();
System.out.println("与客户端:"+accept.getRemoteSocketAddress()+ "连接建立成功...");
//将accpet实例交给子线程处理客户端请求
new SocketHandler(accept).start();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
UDP
无连接的UDP
1.UDP概念:用户数据报协议(UDP,User Datagram Protocol)是无连接、不可靠的数据报协议
2.UDP特点:
- UDP无连接,减少了开销和发送数据时的时延
- UDP尽最大努力交付,不保证可靠交付,不需要维持复杂的连接状态表
- UDP面向报文,对应用程序交付下来的报文,再添加首部后就向下交付网络层
- UDP没有拥塞控制,网络拥塞不会使源主机的发送速率降低,这对实时应用很重要
- UDP支持一对一、一对多、多对一和多对多的交互通信
- UDP的首部开销小,只有8个字节
3.UDP报文段结构
UDP编程
通信过程和网上购物相似
模拟实现
- 客户端向服务器端发送消息
- 客户端
public class MyUDPClient {
public static void main(String[] args) {
//从控制台获取数据
String info = (new Scanner(System.in)).next();
try {
//构造发送数据的对象
DatagramSocket socket = new DatagramSocket();
//将数据打包
DatagramPacket datagramPacket = new DatagramPacket(info.getBytes(),info.length()
, InetAddress.getByName("localhost"),6666);
//发送
socket.send(datagramPacket);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 服务器端
public class MyUDPServer {
public static void main(String[] args) {
try {
//构造接收数据的对象
DatagramSocket socket = new DatagramSocket(6666);
//接收数据空间
byte[] buf = new byte[1024];
//将接收数据空间打包
DatagramPacket dp = new DatagramPacket(buf, 1024);
//数据接收到打包的数据空间中
socket.receive(dp);
socket.send(dp);
//拆包
String info = new String(dp.getData(), 0, dp.getLength());
System.out.println("接收到数据为: "+info);
} catch (IOException e) {
e.printStackTrace();
}
}
}