TCP/UDP头部
TCP头部
- 源端口、目的端口:数据的分用通过端口实现
- 序号:从0~2^32 - 1循环使用、每个字节一个序号、报文段第一个字节序号称为“报文段序号”
- 确认号:接收方期待收到对方下一个报文段的报文段序号,确认号数值设置在确认分组当中
- 数据偏移:数据部分距离报文起始位置,即首部长度,最大为60字节
- 保留:目前置为0,无用
- 控制位
- 紧急URG:URG = 1时,表明报文中有紧急数据,需要与紧急指针配合
- 确认ACK:建立TCP连接后,所有报文段ACK置为1,表明确认号有效
- 推送PSH:当PSH = 1,数据报直接发送。PSH = 0,缓存填满才发送
- 复位RST:RST = 1,TCP连接需要释放并重新建立
- 同步SYN:
SYN = 1、ACK = 0,该报文段是连接请求报文段
SYN = 1、ACK = 1,该报文段是同意连接报文段- 终止FIN:FIN = 1,该报文段请求释放连接
- 窗口:接收方允许发送方传送的数据量
- 检验和:与UDP用户数据报一样
- 紧急指针:紧急指针指出紧急数据的位置
- 选项:窗口扩大、时间戳
UDP头部
- 源端口:接收方回信时选用、不需要时可用全0
- 目的端口:必须使用
- 长度:整个报文长度
- 检验和:检测整个报文
- 伪首部:当UDP数据报需要进行检验时,会在首部生成临时的伪首部。但是伪首部只是UDP暂时的,不属于UDP数据报组成
TCP/UDP区别
TCP面试连接,UDP面向无连接
- TCP面向连接:数据传输前使用三次报文握手建立TCP 连接,TCP 连接建立成功后才能进行数据传输,数据传输结束后使用四报文挥手来释放TCP连接。
- UDP面向无连接:双方进行通信,可以随时发送数据
TCP是可靠的,UDP是不可靠的
- TCP是可靠的:通过接收确认和重传机制,TCP保证数据的正确性以及顺序
- UDP是不可靠的:UDP不保证数据的正确性、顺序,甚至还可能丢包
传输方式
- TCP:只能支持一对一
- UDP: 不仅支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。
TCP面向字节流,UDP面向报文
- TCP面向字节流:TCP基于流的传输表示TCP不认为消息是一条一条的
- UDP面向报文:UDP基于报文的传输标识UDP认为消息是一条一条独立的消息
TCP头部开销大,UDP头部开销小
- TCP头部开销大:至少20个字节
- UDP头部开销小:只有8个字节
TCP具有拥塞控制,UDP没有拥塞控制
- TCP具有拥塞控制
- UDP没有拥塞控制:因此网络出现拥塞不会使源主机的发送速率降低
应用场景
- TCP适用要求可靠传输的应用(文件传输)
- UDP适用实时应用(直播、视频会议、IP电话)
各自问题
- TCP会出现粘包问题:TCP是面向连接的,所以在TCP看来,并没有把消息看成一条条的,而是全部消息在TCP眼里都是字节流,因此容易把多个消息混在一起后,TCP就分不清了
- UDP会出现丢包问题
TCP/UDP项目实战
TCP
TcpClientDemo01
public class TcpClientDemo01 {
public static void main(String[] args) throws IOException {
//1. 创建连接127.0.0.1:9999的Socket
InetAddress serverIp = InetAddress.getByName("127.0.0.1");
int port = 9999;
Socket socket = new Socket(serverIp,port);
//2. 创建对127.0.0.1:9999输出内容的输出流
OutputStream os = socket.getOutputStream();
os.write("你好".getBytes());
//3. 关闭socket与IO流
os.close();
socket.close();
}
}
TcpServerDemo01
public class TcpServerDemo01 {
public static void main(String[] args) throws IOException {
//1. 创建服务器Socket用于监听客户端Socket
ServerSocket serverSocket = new ServerSocket(9999);
//2. 创建连接监听到客户端的Socket
Socket socket = serverSocket.accept();
//3. 创建连接被监听的Socket的输入流
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer))!=-1){
baos.write(buffer,0,len);
}
System.out.println(baos.toString());
//4. 关闭socket与IO流
baos.close();
is.close();
socket.close();
serverSocket.close();
}
}
UDP
UdpClientDemo01
public class UdpClientDemo01 {
public static void main(String[] args) throws IOException {
//1. 建立一个Socket
DatagramSocket socket = new DatagramSocket();
//2. 建立数据报
String msg = "你好呀";
InetAddress localhost = InetAddress.getByName("127.0.0.1");
int port = 9090;
DatagramPacket packet = new DatagramPacket(msg.getBytes(),0,msg.getBytes().length,localhost,port);
//3. 发送数据报
socket.send(packet);
//4. 关闭socket
socket.close();
}
}
UdpServerDemo01
public class UdpServerDemo01 {
public static void main(String[] args) throws IOException {
//1. 建立一个socket
DatagramSocket socket = new DatagramSocket(9090);
//2. 接收数据报
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
socket.receive(packet);
System.out.println(new String(packet.getData(),0, packet.getLength()));
socket.close();
}
}