一、单播
-
UDP协议的特点:
-
无连接 、不保证传输可靠(可能重复到达、失序、丢失、无字节流控制(数据传输快的会淹没慢的))
-
UDP传输
-
-
UDP 服务端(接收端)的搭建流程
-
UDP客户端(发送端)的搭建流程
- 通信流程
-
sendto 和 recvfrom
-
这两个函数一般在使用UDP协议时使用
-
sendto
-
功能: sendto - send a message on a socket
头文件:
#include <sys/socket.h>
函数原型:
ssize_t sendto(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len);
参数说明:
int socket: 通信套接字
const void *message: 要发送的数据(消息)
size_t length:发送的长度
int flags:发送的方式: 默认 0
const struct sockaddr *dest_addr: 要发送的目标地址:(指定对方的ip等)
socklen_t dest_len: 大小
返回值:
成功: 返回成功的字节数
失败: 返回-1并设置errno
- recvfrom
功能: recvfrom - receive a message from a socket
头文件:
#include <sys/socket.h>
函数原型:
ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
int flags, struct sockaddr *restrict address,
socklen_t *restrict address_len);
参数说明:
int socket: 通信套接字
void *restrict buffer: 接收保存数据(消息)
size_t length:发送的长度
int flags:发送的方式: 默认 0
struct sockaddr *restrict address:对方的ip
socklen_t *restrict address_len: 地址长度
返回值:
成功: 返回成功的字节数
失败: 返回-1并设置errno
单播就是普通版的UDP 服务器和客户端
代码示例
服务器端
/*===============================================
* 文件名称:UdpServer.c
* 创 建 者:
* 创建日期:
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
/*
if( argc < 3 )
{
puts("arg err");
return -1;
}
*/
//创建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//准备需要发送数据的服务器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
.sin_port = htons(8888),
.sin_addr.s_addr = inet_addr("0")
};
//绑定
int ret = bind(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("bind ");
return -1 ;
}
//发送数据
char buf[BUFSIZ] = {0};
while(1)
{
memset(buf,0,BUFSIZ);
ret = recvfrom(sockfd,buf,BUFSIZ,0,NULL,NULL);
if( -1 == ret)
{
perror("recv");
return -1;
}
// sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
puts(buf);
}
close(sockfd);
return 0;
}
客户端
/*===============================================
* 文件名称:UdpClient.c
* 创 建 者:
* 创建日期:2023年08月25日
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//创建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//准备需要发送数据的服务器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
//.sin_port = htonl(atoi(argv[2])),
.sin_port = htons(8888),
//.sin_addr.s_addr = inet_addr(argv[1])
.sin_addr.s_addr = inet_addr("192.168.18.196")
};
//发送数据
char buf[BUFSIZ] = {0};
char rbuf[BUFSIZ] = {0};
while(1)
{
fgets(buf,sizeof(buf),stdin);
int ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("sendto fail");
return -1;
}
//recvfrom(sockfd,rbuf,BUFSIZ,0,NULL,NULL);
//
puts(buf);
}
close(sockfd);
return 0;
}
二、广播
定义:给同一网段的所有主机 发送 数据
如何实现:需要给发送端
开启 广播权限,并且 发送的目标地址是 广播地址
代码示例
服务器端文章来源:https://www.toymoban.com/news/detail-756167.html
/*===============================================
* 文件名称:UdpServer.c
* 创 建 者:
* 创建日期:
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//创建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//准备需要发送数据的服务器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
.sin_port = htons(6666),
.sin_addr.s_addr = inet_addr("0")
};
//绑定
int ret = bind(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("bind ");
return -1 ;
}
//发送数据
char buf[BUFSIZ] = {0};
while(1)
{
memset(buf,0,BUFSIZ);
ret = recvfrom(sockfd,buf,BUFSIZ,0,NULL,NULL);
if( -1 == ret)
{
perror("recv");
return -1;
}
// sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
puts(buf);
}
close(sockfd);
return 0;
}
客户端
/*===============================================
* 文件名称:UdpClient.c
* 创 建 者:
* 创建日期:
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
//创建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//准备需要发送数据的服务器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
//.sin_port = htonl(atoi(argv[2])),
.sin_port = htons(6666),
//.sin_addr.s_addr = inet_addr(argv[1])
.sin_addr.s_addr = inet_addr("192.168.18.255") //广播地址
};
//开播广播权限
int opt = 1 ;
// setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
//
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt));
//发送数据
char buf[BUFSIZ] = {0};
char rbuf[BUFSIZ] = {0};
while(1)
{
fgets(buf,sizeof(buf),stdin);
int ret = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("sendto fail");
return -1;
}
}
close(sockfd);
return 0;
}
三、组播(多播)
- 有选择的接收 客户端的数据
- 是在
接收端
加入多播组
组播在发送者和每一接收者之间实现点对多点网络连接。如果一台发送者同时给多个接收者传输相同的数据,也只需
复制一份相同的数据包。它提高了数据传送效率,减少了骨干网络出现拥塞的可能性。组播解决了单播和广播方式
效率低的问题。当网络中的某些用户需求特定信息时,组播源(即组播信息发送者)仅发送一次信息,组播路由器借助
组播路由协议为组播数据包建立树型路由,被传递的信息在尽可能远的分叉路口才开始复制和分发。
代码示例(服务器端)文章来源地址https://www.toymoban.com/news/detail-756167.html
/*===============================================
* 文件名称:UdpServer.c
* 创 建 者:
* 创建日期:
* 描 述:
================================================*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
/*
if( argc < 3 )
{
puts("arg err");
return -1;
}
*/
//创建套接字
int sockfd = socket(AF_INET ,SOCK_DGRAM,0);
if( -1 == sockfd )
{
perror("socket fail");
return -1;
}
//准备需要发送数据的服务器ip和端口
struct sockaddr_in ser_addr = {
.sin_family = AF_INET ,
.sin_port = htons(8888),
.sin_addr.s_addr = inet_addr("0")
};
//组播
struct ip_mreqn group = {
.imr_multiaddr.s_addr = inet_addr("224.224.224.224"),//组播地址:224.0.0.1——239
.imr_address.s_addr =htonl(INADDR_ANY)//绑定本机ip
};
//设置组播权限
if( -1 == setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&group,sizeof(group)))
{
perror("setsocket");
return -1;
}
//绑定
int ret = bind(sockfd,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
if( -1 == ret )
{
perror("bind ");
return -1 ;
}
//发送数据
char buf[BUFSIZ] = {0};
while(1)
{
memset(buf,0,BUFSIZ);
ret = recvfrom(sockfd,buf,BUFSIZ,0,NULL,NULL);
if( -1 == ret)
{
perror("recv");
return -1;
}
// sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&ser_addr,sizeof(ser_addr));
puts(buf);
}
close(sockfd);
return 0;
}
客户端
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */ //man socket
#include <sys/socket.h>
#include <sys/socket.h> // man 7 ip
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h> //man 3 inet_addr
#include <netinet/in.h>
#include <arpa/inet.h> //man 2 read
#include <unistd.h>
#define SIZE 1024
#define SERV_IP "0"
#define SERV_PORT 6666
//UDP 客户端
int main(int argc,const char *argv[])
{
int connfd;
int ret;
//1. socket
connfd = socket(AF_INET, SOCK_DGRAM, 0); // udp:SOCK_DGRAM
if(-1 == connfd)
{
perror("socket");
return -1;
}
//2. 填充ip 要连接的目标 ip 和端口
struct sockaddr_in dest_addr = {
.sin_family = AF_INET,
.sin_port = htons(SERV_PORT),
.sin_addr.s_addr = inet_addr("127.0.0.1")
};
//4.通信
char buf[SIZE] = {0};
while(1)
{
fgets(buf, sizeof(buf)-1, stdin);
if(0 == strncmp(buf, "quit",4))
{
break;
}
sendto(connfd, buf, sizeof(buf), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
}
//关闭套接字
close(connfd);
return 0;
}
到了这里,关于网络编程(三)—— UDP(单播、广播、组播)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!