目录
[4.1 概念](#4.1 概念)
[4.2 特点](#4.2 特点)
[5.1 服务器udpser](#5.1 服务器udpser)
[5.2 客户端udpcil](#5.2 客户端udpcil)
一、TIME_WAIT状态存在的原因
1.可靠的终止TCP连接。
2.保证让迟来的TCP报文段有足够的时间被识别并丢弃。
二、TIME_WAIT状态存在的意义
TIME_WAIT状态存在的主要目的是为了确保已传输的数据在网络中正确地到达目的地,同时避免出现数据包重复发送或混乱的情况。
三、TIME_WAIT状态的作用
-
确保数据传输的完整性:在发送端完成数据传输后,主动关闭连接的一方会进入TIME_WAIT状态,此时会等待一段时间,以确保对方接收到了所有数据,并且成功响应了关闭连接的请求。这样可以保证数据的完整性,避免数据丢失或损坏。
-
防止出现混乱的连接状态:TIME_WAIT状态可以确保在一段时间内不会重用相同的本地端口和远程端口的连接,防止新的连接与之前的连接混淆,导致数据混乱或连接失败。
-
处理延迟的数据包:在TIME_WAIT状态下,可以处理由于网络延迟而导致的延迟数据包,以确保数据传输的顺利完成。此外,TIME_WAIT状态还可以避免在网络中产生冲突或重复数据包发送的情况。
简而言之,TIME_WAIT状态的存在可以确保数据传输的可靠性和完整性,同时避免网络连接的混乱和冲突,提高网络通信的稳定性和可靠性。
四、UDP的基本概念
4.1 概念
UDP(User Datagram Protocol,用户数据报协议)是一种无连接的、简单和高效 的网络传输协议。UDP提供了一种不可靠的、无序的数据传输服务,相比于TCP协议,UDP不具备建立连接、可靠传输和数据重传等特性。
总的来说,UDP是一种简单、高效的传输协议,适用于对数据传输速度和实时性要求较高,对数据准确性要求较低的场景。
4.2 特点
-
无连接:UDP不需要像TCP那样建立连接和维护状态,因此可以更快速地传输数据。每个UDP数据包都是独立的,发送方和接收方之间没有直接的关联,因此UDP适用于实时性要求较高的应用场景。
-
不可靠性:UDP不提供可靠的数据传输服务,数据包可能丢失、重复或乱序到达,接收方无法检测到这些问题。因此,在对数据的准确性要求不那么高的场合,可以选择UDP协议进行数据传输。
-
面向报文:UDP 对应用程序交下来的报文,在添加首部后就向下交付给 IP 层,既不拆分也不合并,保留报文边界 。这要求应用程序选择合适报文大小 。
-
简单和高效:UDP的头部信息较简单,不像TCP那样需要维护连接状态和处理复杂的传输控制。这使得UDP在一些对实时性和效率要求较高的应用场景中具有优势,比如音视频传输、在线游戏等。
五、模拟实现UDP服务器和客户端收发数据

5.1 服务器udpser
cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1)
{
exit(1);
}
struct sockaddr_in saddr,caddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
if(res==-1)
{
printf("bind err\n");
exit(1);
}
while(1)
{
int len =sizeof(caddr);
char buff[128]={0};
recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);//接收数据,可能会阻塞
printf("buff=%s\n",buff);
sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));
}
}
首先,在main函数中创建一个UDP套接字(sockfd):通过调用socket函数创建了一个IPv4协议的数据报套接字。如果创建失败,则程序退出。
然后,初始化服务器地址结构体saddr:设置地址族为AF_INET(IPv4)、端口号为6000,并将IP地址设置为本地回环地址"127.0.0.1"。
进行绑定:使用bind函数将套接字与服务器地址绑定。如果绑定失败,输出错误信息并退出程序。
进入循环:程序进入一个无限循环,等待接收客户端发送的数据包。
调用recvfrom函数接收数据:recvfrom会阻塞等待客户端发来的数据包,一旦接收到数据包,将数据存储在buff数组中,并打印出接收到的数据内容。
调用sendto函数发送数据:sendto函数将"ok"字符串回复给客户端,回复的目标地址是客户端的地址(caddr)。
5.2 客户端udpcil
cpp
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
int main()
{
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1)
{
exit(1);
}
struct sockaddr_in saddr;//代表服务器ip和端口
saddr.sin_family=AF_INET;
saddr.sin_port=htons(6000);
saddr.sin_addr.s_addr=inet_addr("127.0.0.1");
while(1)
{
printf("input:\n");
char buff[128]={0};
fgets(buff,128,stdin);
if(strncmp(buff,"end",3)==0)
{
break;
}
sendto(sockfd,buff,strlen(buff)-1,0,(struct sockaddr*)&saddr,sizeof(saddr));
memset(buff,0, 128);
int len =sizeof(saddr);
recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);
printf("buff=%s\n",buff);
}
}
在main函数中创建一个UDP套接字(sockfd):通过调用socket函数创建了一个IPv4协议的数据报套接字。如果创建失败,则程序退出。
初始化服务器地址结构体saddr:设置地址族为AF_INET(IPv4)、端口号为6000,并将IP地址设置为本地回环地址"127.0.0.1"。
进入循环:程序进入一个无限循环,每次循环都提示用户输入消息并发送给服务器。
用户输入消息:使用fgets函数从标准输入(stdin)读取用户输入的消息存储在buff数组中。如果用户输入"end",则跳出循环。
发送数据给服务器:调用sendto函数将用户输入的消息发送给服务器。
接收服务器的回复:调用recvfrom函数从服务器接收回复消息,将回复消息存储在buff数组中,并打印出来。
循环结束:如果用户输入"end"则退出循环,结束程序。
运行结果:
