转载自:
https://blog.csdn.net/fanle93/article/details/90666484
UDP(User Datagram Protocol)即用户数据报协议,是OSI(Open System Interconnection,即开放式系统互联)参考模型中的一种传输层协议。
该协议提供了一种面向无连接模式的通信。由于这种特性,使用UDP协议进行传输时的开销更小,但同时并不能保证被传输的数据能够到达目的地。
总结一下UDP协议的一些特性:
TCP(Transmission Control Protocol)即传输控制协议,与UDP协议一样,是OSI参考模型中的一种传输层协议。
为了明晰UDP协议与TCP协议两者之间的区别,有必要对TCP的一些特性进行简要的了解。
UDP | TCP |
---|---|
面向无连接 | 面向有连接 |
支持一对一、一对多、多对一、和多对多的通信 | 只能有两个端点,实现一对一的通信 |
不保证数据传输的可靠性 | 传输数据无差错,不丢失,不重复,且按时序到达 |
占用资源较少 | 占用资源较多 |
基于以上特性,UDP协议更适合应用于:
本文提供了两个操作系统下,UDP通信的代码。
#include
#include
#include
#include
#include
//第一个传参,目的ip地址
//第二个传参,目的端口号
int main(int argc, char *argv[])
{
//输出参数数量校验
if (argc < 3)
{
printf(“输入的参数数量错误!\n”);
printf(“请检查并重新执行此程序!\n");
return -1;
}
char buf[1000] = { "hello world" }; //声明发送数据缓存区
struct sockaddr_in sockaddr_dest; //声明接收服务器地址
int fd = socket(AF_INET, SOCK_DGRAM, 0); //建立socket
//AF_INET IPV4
//SOCK_DGRAM UDP
//0 传输层通信
//socket建立测试
if (client_fd < 0)
{
printf("socket建立失败!\n");
return -1;
}
//清空接收服务器地址
memset(&client_addr, 0, sizeof(sockaddr_dest));
//配置接收端服务器
sockaddr_dest.sin_family = AF_INET; //ipv4
sockaddr_dest.sin_addr.s_addr = inet_addr(argv[1]); //第一个传参,ip地址
sockaddr_dest.sin_port = htons(atoi(argv[2])); //第二个传参,端口号
//发送数据
sendto(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr_dest, sizeof(sockaddr_dest));
//关闭socket
close(fd);
}
#include
#include
#include
//第一个传参,本机ip地址
//第二个传参,本机端口号
int main(int argc, char *argv[])
{
//输出参数数量校验
if (argc < 3)
{
printf(“输入的参数数量错误!\n”);
printf(“请检查并重新执行此程序!\n");
return -1;
}
int len = sizeof(struct sockaddr_in);
char buf[100] = { 0 };
struct sockaddr_in sockaddr_recv; //接收端通信地址结构
struct sockaddr_in sockaddr_send; //发送端通信地址结构
int fd = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_recv.sin_family = AF_INET;
sockaddr_recv.sin_port = htons(33333);
sockaddr_recv.sin_addr.s_addr = htonl(INADDR_ANY);
//绑定socket
int ret = bind(fd, (struct sockaddr *)&sockaddr_recv, sizeof(sockaddr_recv));
//判断是否绑定成功
if (ret == 0)
{
printf("绑定成功!\n");
}
else
{
printf("绑定失败!\n");
}
//以阻塞端方式接收数据
recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sockaddr_send, &len);
//打印接收到的数据
printf("recv is %s\n", buf);
}
#include
#include
#include
#include
#include
#include
//第一个传参,本机ip地址
//第二个传参,本机端口号
//第三个船餐,等待时间,单位秒
int main(int argc, char *argv[])
{
//输出参数数量校验
if (argc < 4)
{
printf(“输入的参数数量错误!\n”);
printf(“请检查并重新执行此程序!\n");
return -1;
}
int len = sizeof(struct sockaddr_in);
char buf[100] = { 0 };
struct sockaddr_in sockaddr_recv; //接收端通信地址结构
struct sockaddr_in sockaddr_send; //发送端通信地址结构
int fd = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_recv.sin_family = AF_INET;
sockaddr_recv.sin_port = htons(33333);
sockaddr_recv.sin_addr.s_addr = htonl(INADDR_ANY);
//绑定socket
int ret = bind(fd, (struct sockaddr *)&sockaddr_recv, sizeof(sockaddr_recv));
//判断是否绑定成功
if (ret == 0)
{
printf("绑定成功!\n");
}
else
{
printf("绑定失败!\n");
}
//使用select完成非阻塞
fd_read read; //声明一个fd_set集合来保存被检测的句柄
struct timeval timeout; //声明一个时间结构来保存阻塞的时间
//循环接收
while(1)
{
FD_ZERO(&read); //使用select函数之前先将集合清零
FD_SET(fd, &read); //将所要检测端socket句柄加入到集合中
timeout.tv_sec = atoi(argv[3]); //设置select等待的最大时间
timeout.tv_usec = 0;
int ret_select = select(4, &read, NULL, NULL, &timeout); //检测集合read中的句柄是否有可读信息
//如果返回值小于0,则select函数出错
if (ret_select < 0)
{
printf("select函数出错!\n");
return -1;
}
//如果返回值为0,则在计时周期内socket的状态没有发生改变
else if (ret_select == 0)
{
printf("此周期内无数据接收!\n");
sleep(1); //无数据接收,等待1秒
}
//ret_select记录了发生变化的句柄的个数
else
{
if (FD_ISSET(fd, &read)) //如果这个被监视端句柄真的变为可读了
{
memset(buf, 0, 100); //先将接收缓存区清零
len = sizeof(sockaddr_send); //获取发送端通信地址结构长
//在这一时间周期内以阻塞的方式接收数据
int recv = recvfrom(server_fd, buf, BUF_LEN, 0, (struct sockaddr *)&sockaddr_send, &len);
//判断是否接收到了数据
if (recv == -1)
{
printf("接收数据失败!\n");
return -1;
}
printf("recv is %s\n", buf);
}
}
}
}
int Deploy_UDP(int &skt, char *IP_Address, UINT port)
{
skt = socket(AF_INET, SOCK_DGRAM, 0);
struct sockaddr_in svrsockaddr;
svrsockaddr.sin_family = AF_INET;
svrsockaddr.sin_port = htons(port);
svrsockaddr.sin_addr.S_un.S_addr = inet_addr(IP_Address);
int result_bind = bind(skt, (struct sockaddr FAR*)&svrsockaddr, sizeof(struct sockaddr_in));
//设置UDP的模式为非阻塞接收
u_long unblock=100;
int result_unblock = ioctlsocket(skt, FIONBIO, &unblock);
return 0;
}
int shareSend(int skt, char *buffer, int len, char *IP_Address, UINT port)
{
sockaddr_in Comsockaddr;
Comsockaddr.sin_family = AF_INET;
Comsockaddr.sin_port = htons(port);
Comsockaddr.sin_addr.S_un.S_addr = inet_addr(IP_Address);
return sendto(skt, buffer, len, 0, (struct sockaddr FAR*)&Comsockaddr, sizeof(sockaddr_in));
}
int UDPRecv(int skt, BYTE *buffer, int len, struct sockaddr_in &recvsock)
{
int len_recvsock = sizeof(struct sockaddr_in);
if (skt > 0)
{
return recvfrom(skt, (char *)buffer, len, 0, (struct sockaddr FAR*)&recvsock, &len_recvsock);
}
return -1;
}
int UDPClose(int skt)
{
closesocket(skt);
return 0;
}