Linux 网络应用开发–-单播、广播和组播

关于TCP和UDP区别

TCP 和 UDP 他是都是网络当中的进程进行通信的,但是他们面向的群体或者是对象是 不同的,TCP 他是一对一的,一个服务器对应一个客户端,并且他在消息发送之前会和客户 端进行,三次握手,断开的会进行四次挥手.

 UDP 他是无连接的,不可靠的,会造成消 息的丢失,因为他在发送消息的时候,不会给接受者建立连接,所以他根本不关心对方有没 有没有收到消息。

单播、广播和组播

三者都是使用 UDP 协议进行数据传输的。可以这样理解, 客户端和服 务器相互通信前不需要建立连接,直接向指定的对方 ip 地址和端口号发送数据, 无论对方 是否存在,是否在线,以及是否收到数据,均不用关心。

三者区别

单播:用于两个主机之间的端对端通信;

广播:用于一个主机对整个局域网上所有主机上的数据通信,网络中的所有主机都会接 收同一份数据副本;

 组播:用于对一组特定的主机进行通信,且这个特定的组内主机可以动态添加和删除多 台主机,组内所有主机收到相同一份数据副本

单播过程

服务器端

创建套接字 ->填写核心结构体( 1.网络类型 2.IP 地址 3.端口号) ->绑定 ->数据收发 ->关闭套接字

socket()->bind()->sendto()/recvfrom()->close()

客户端

创建套接字 ->填写核心结构体 (网络类型 2.IP 地址 3.端口号) ->数据收发 ->关闭套接字

socket()->sendto()/recvfrom()->close()

代码示例

//服务器
#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <unistd.h> 
int main() 
{ 
 int serfd = socket(AF_INET,SOCK_DGRAM,0); 
 if(serfd < 0) 
 { 
 perror("socket"); 
 return -1; 
 } 
 printf("创建套接子成功\n"); 
 struct sockaddr_in seraddr,cliaddr; 
 memset(&seraddr,0,sizeof(seraddr)); 
 seraddr.sin_family = AF_INET; 
 seraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
 seraddr.sin_port = htons(6666); 
 int bin = bind(serfd,(struct sockaddr*)&seraddr,sizeof(seraddr)); 
 if(bin < 0) 
 { 
 perror("bind"); 
 return -1; 
 } 
 printf("绑定成功\n"); 
 char buf[256]; 
 socklen_t len = sizeof(cliaddr);  while(1) 
 { 
 memset(buf,0,sizeof(buf)); 
 recvfrom(serfd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,&len); 
 printf("buf:%s\n",buf); 
 memset(buf,0,sizeof(buf)); 
 printf("请输入发送的消息:"); 
 scanf("%s",buf); 
 sendto(serfd,buf,sizeof(buf),0,(struct sockaddr*)&cliaddr,len); 
 } 
 close(serfd); 
 return 0; 
} 
//客户端
#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <unistd.h> 
int main() 
{ 
 int serfd = socket(AF_INET,SOCK_DGRAM,0); 
 if(serfd < 0) 
 { 
 perror("socket"); 
 return -1; 
 } 
 printf("创建套接子成功\n"); 
 struct sockaddr_in seraddr; 
 memset(&seraddr,0,sizeof(seraddr)); 
 seraddr.sin_family = AF_INET; 
 seraddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
 seraddr.sin_port = htons(6666); 
 char buf[256]; 
 socklen_t len = sizeof(seraddr); 
 while(1) 
 { 
 memset(buf,0,sizeof(buf)); 
 printf("请输入发送的消息:"); 
 scanf("%s",buf); 
 sendto(serfd,buf,sizeof(buf),0,(struct sockaddr*)&seraddr,len); 
 memset(buf,0,sizeof(buf));  recvfrom(serfd,buf,sizeof(buf),0,(struct sockaddr*)&seraddr,&len); 
 printf("buf:%s\n",buf); 
 } 
 close(serfd); 
 return 0; 
} 

组播过程

---发送端调用流程如下:

1) 创建套接字; socket

2) 填写的核心结构体;

struct ip_mreqn ipaddr;

ipaddr.imr_address.s_addr = inet_addr(IP);

ipaddr.imr_ifindex = if_nametoindex("ens33");

ipaddr.imr_multiaddr.s_addr = inet_addr("多播组的地址");

setsockopt();

3) 填写 socket 的核心结构体;

struct sockaddr_in seraddr;

seraddr.sin_family = AF_INET;

seraddr.sin_port = htons(PORT);

seraddr.sin_addr.s_addr = inet_addr("多播组的地址");

4) 向多播地址发送数据; sendto();

5) 关闭套接字; close();

---接收端调用流程如下:

1) 创建套接字; socket

2) 填写核心结构体;

struct sockaddr_in addr;

addr.sin_family = AF_INET;

addr.sin_port = htons(发送者的端口号);

addr.sin_addr.s_addr = htonl(INADDR_ANY);//自动获取自己的 IP

3) 绑定 socket; bind();

4) 设置加入多播组核心结构体;

struct ip_mreqn ipaddr;

ipaddr.imr_address.s_addr = inet_addr(发送者的 IP);

ipaddr.imr_ifindex = if_nametoindex("ens33");

ipaddr.imr_multiaddr.s_addr = inet_addr("多播组的 IP");

5) 加入播播组; setsockopt();

6) 开始循环,接收数据; recvfrom()

7) 关闭套接字; close();

代码示例

//发送端
#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/types.h> #include <netinet/in.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <unistd.h> 
#include <net/if.h> 
int main() 
{ 
 int serfd = socket(AF_INET,SOCK_DGRAM,0); 
 if(serfd<0) 
 { 
 perror("socket"); 
 return -1; 
 } 
 struct ip_mreqn ipaddr; 
 ipaddr.imr_address.s_addr = inet_addr("192.168.110.190"); 
 ipaddr.imr_ifindex = if_nametoindex("ens33"); 
 ipaddr.imr_multiaddr.s_addr = inet_addr("224.6.6.6"); 
 setsockopt(serfd,IPPROTO_IP,IP_MULTICAST_IF,&ipaddr,sizeof(ipaddr)); 
 struct sockaddr_in seraddr; 
 seraddr.sin_family = AF_INET; 
 seraddr.sin_port = htons(8888); 
 seraddr.sin_addr.s_addr = inet_addr("224.6.6.6"); 
 char buf[20]="正在广播"; 
 while(1) 
 { 
 sendto(serfd,buf,sizeof(buf),0,(struct sockaddr*)&seraddr,sizeof(seraddr)); 
 sleep(1); 
 } 
 close(serfd); 
 return 0; 
} 
//接收端
#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <unistd.h> 
#include <net/if.h> 
int main() 
{ 
 int serfd = socket(AF_INET,SOCK_DGRAM,0);  if(serfd<0) 
 { 
 perror("socket"); 
 return -1; 
 } 
 struct sockaddr_in addr; 
 addr.sin_family = AF_INET; 
 addr.sin_port = htons(8888); 
 addr.sin_addr.s_addr = htonl(INADDR_ANY);//自动获取自己的 IP 
 int bin = bind(serfd,(struct sockaddr*)&addr,sizeof(addr)); 
 if(bin < 0) 
 { 
 perror("bind"); 
 return -1; 
 } 
 struct ip_mreqn ipaddr; 
 ipaddr.imr_address.s_addr = inet_addr("192.168.110.190"); 
 ipaddr.imr_ifindex = if_nametoindex("ens33"); 
 ipaddr.imr_multiaddr.s_addr = inet_addr("224.6.6.6"); 
 setsockopt(serfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&ipaddr,sizeof(ipaddr)); 
 char buf[20]; 
 socklen_t len = sizeof(addr); 
 while(1) 
 { 
 memset(buf,0,sizeof(buf)); 
 recvfrom(serfd,buf,sizeof(buf),0,(struct sockaddr*)&addr,&len); 
 printf("buf:%s\n",buf); 
 } 
 close(serfd); 
 return 0; 
} 

广播过程

---广播包发送流程如下:

1) 创建 UDP 套接字;

socket(AF_INET, SOCK_DGRAM, 0)

2) 填充广播信息结构体;struct sockaddr_in

3) 设置套接字选项允许发送广播包;

setsockopt(, ,SO_BROADCAST, ,)

4) 发送数据包;sendto( )

5)关闭套接字

---广播包接收流程如下:

1) 创建 UDP 套接字;

socket(AF_INET, SOCK_DGRAM, 0)

2) 填充广播信息结构体;struct sockaddr_in

3) 绑定地址和端口;bind( )

4) 接收数据包;recvfrom( )

5)关闭套接字

代码示例

//发送者 
#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <unistd.h> 
int main() 
{ 
 int serfd = socket(AF_INET,SOCK_DGRAM,0); 
 if(serfd < 0) 
 { 
 perror("socket"); 
 return -1; 
 } 
 printf("创建套接子成功\n"); 
 struct sockaddr_in seraddr; 
 memset(&seraddr,0,sizeof(seraddr)); 
 seraddr.sin_family = AF_INET; 
 seraddr.sin_addr.s_addr = inet_addr("192.168.110.255"); 
 seraddr.sin_port = htons(6666); 
 int n = 1; 
 setsockopt(serfd,SOL_SOCKET,SO_BROADCAST,&n,sizeof(n));//设置广播 
 char buf[256]; 
 socklen_t len = sizeof(seraddr);  int num = 1; 
 int sto = 0; 
 while(1) 
 { 
 num++; 
 sendto(serfd,&num,4,0,(struct sockaddr*)&seraddr,len); 
 //if(sto < 0) 
 //{ 
 //perror("sento error\n"); 
 //} 
 sleep(1); 
 //printf("sento ok\n"); 
 } 
 close(serfd); 
 return 0; 
} 
//接收者 
 
#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <string.h> 
#include <unistd.h> 
int main() 
{ 
 int serfd = socket(AF_INET,SOCK_DGRAM,0); 
 if(serfd < 0) 
 { 
 perror("socket"); 
 return -1; 
 } 
 printf("创建套接子成功\n"); 
 struct sockaddr_in seraddr; 
 memset(&seraddr,0,sizeof(seraddr)); 
 seraddr.sin_family = AF_INET; 
 seraddr.sin_addr.s_addr = htonl(INADDR_ANY);//自动获取当前的 ip 地址 192.168.15.10 
 seraddr.sin_port = htons(6666); 
 int bin = bind(serfd,(struct sockaddr*)&seraddr,sizeof(seraddr)); 
 if(bin < 0) 
 { 
 perror("bind");  return -1; 
 } 
 printf("绑定成功\n"); 
 char buf[256]; 
 socklen_t len = sizeof(seraddr); 
 int num = 0; 
 while(1) 
 { 
 recvfrom(serfd,&num,4,0,(struct sockaddr*)&seraddr,&len); 
 printf("num:%d\n",num); 
 } 
 close(serfd); 
 return 0; 
} 

专用函数

函数功能:设置组播属性

函数原型:int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen)  函数参数:sockfd:套接字的描述符

                  level:网络通信的层 等级的 -- 层 -- 网络的那一层

                            IPPROTO_IP: -- IP 层 -- 组播(man 7 ip) 专门组播 --- 你就填这个宏

                            SOL_SOCKET:专门用于底层的地址释放层

                                        0 代表 -- disable --关闭功能(默认) 1 代表 -- enable -- 打开功能

                  optname:选项 IPPROTO_IP:

                                         IP_ADD_MEMBERSHIP:加入多播组

                                         IP_MULTICAST_IF:创建一个多播组

                                  SOL_SOCKET: SO_REUSEADDR:

                                   当套接字关闭立刻释放底层 IP

                    optval:根据你传入的 optname 选项不一样 参数也不一样

                    optlen : optval 的字节长度

UDP 专用的发送和接收函数

函数功能:发送消息

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen)

函数参数:sockfd:套接字

                  buf:发送消息的缓冲区

                  len:发送消息长度

                 flags:写 0 代表阻塞 --- 不满足就阻塞

                 dest_addr:核心结构体,还是 struct sockaddr_in

                 addrlen:核心结构体的长度

函数返回值:成功发送数据的大小 失败-1

函数功能:接收消息

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen)

函数参数:sockfd:套接字

                 buf:接收消息的缓冲区

                 len:接收消息长度

                 flags:写 0 代表阻塞 --- 不满足就阻塞

                 dest_addr:核心结构体,还是 struct sockaddr_in

                addrlen:核心结构体的长度 --- 需要取这个变量地址

函数返回值:成功接收数据的长度 失败-1

多播专用核心结构体

struct ip_mreqn {

                                struct in_addr imr_multiaddr;//多播组地址

                                struct in_addr imr_address; //你本身的地址

                                int imr_ifindex; //物理硬件 ID 号-- //

                                if_nametoindex("ens33");//获取硬件物理编号 //  };

struct in_addr {

                        unsigned long s_addr; };

  • 28
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值