Linux 网络编程 全解(九)--------UDP和组播实现

版权声明:本BLOG上原创文章未经本人许可,不得转载,否则属于侵权行为 https://blog.csdn.net/weixin_40204595/article/details/84447046

写在前面:本文分两部分,先说UDP的实现,再讲下组播的实现。

正文:

一、

1、TCP和UDP通信优缺点


   TCP:面向连接的,可靠数据包传输。对于不稳定的网络层,采取完全弥补的通信方式,丢包重传机制。

     优点:稳定,数据流量稳定,速度稳定,顺序稳定。

     缺点:传输速度慢,传输效率低,资源开销大。

     使用场景:数据的完整性要求较高、不追求效率。大数据传输、文件传输。 

  
  UDP:无连接的,不可靠的数据报传输。对于不稳定的网络层,采取完全不弥补的通信方式,默认还原网络状况。


     优点:传输速度快、效率高、资源开销小。

     缺点:不稳定。数据流量不稳定、速度不稳定、顺序不稳定。

     使用场景:时效性要求较高,稳定性其次,游戏、视频会议、视频电话。

2、UDP相关的几个API:recvfrom和sendto函数
   ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
   sockfd: 套接字

   buf:缓冲区地址

   flags:0

   src_addr: 传出参数,对端地址结构。

   addrlen:传入传出

   返回值:成功:返回接受的字节数。  -1,失败。0,对端关闭。
  
 ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
  socket:套接字
  buf:缓冲区

  len:数据长度

  flags:0  

  dest_addr:传入参数,目标地址结构

  addrlen:地址结构长度

  返回值: 成功:发送的字节数; -1,失败; 
 

二、UDP Server和UDP Client的实现

    基于TCP的CS模型,其实UDP的CS模型只不过就是砍掉了三次握手,下面贴代码:

   UDP Server:

#include <stdio.h>
#include <sys/types.h>       
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>

#define SER_PORT (8888)

int main(void)
{
	int sockfd = -1;
	struct sockaddr_in ser_ip,cli_ip;
	ssize_t rev_size = 0;
	unsigned char rd_buf[1024] = {0};
	unsigned char *pStr = "Server recv OK";
	socklen_t cli_addr_len = sizeof(struct sockaddr_in) ;
	
	
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	
	memset(&ser_ip,0,sizeof(ser_ip));
	ser_ip.sin_family = AF_INET;
	ser_ip.sin_port = htons(SER_PORT);
	ser_ip.sin_addr.s_addr = htonl(INADDR_ANY);
	
    bind(sockfd, (const struct sockaddr *)&ser_ip,sizeof(ser_ip));
	
	printf("server prepared OK\n");
	
	while(1)
	{
		memset(rd_buf,0,1024);
		rev_size = recvfrom(sockfd, rd_buf, 1024, 0,
                        (struct sockaddr *)&cli_ip, &cli_addr_len);
						
						
		printf("server role : rev_size = %d, cilent port = %d ,recv context: %s\n  ",rev_size,ntohs(cli_ip.sin_port),rd_buf);
		
		sendto(sockfd, pStr, strlen(pStr), 0,(const struct sockaddr *)&cli_ip, cli_addr_len);
		
		sleep(5);
								
	}
	
	return 0;
}

  UDP Client:

#include "stdio.h"
#include <sys/types.h>        
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>


#define SER_PORT (8888)

int main(void)
{
	int sockfd = 0;
	const unsigned char * pSendBuf = "This is client";
	struct sockaddr_in ser_ip;
	const char * ser_ip_addr = "127.0.0.1";
	unsigned int  dst_ip_addr;
	unsigned char rd_buf[1024] = {0};
	int rev_size = 0;
	
	ser_ip.sin_family = AF_INET;
	ser_ip.sin_port = htons(SER_PORT);
	inet_pton(AF_INET, ser_ip_addr, &dst_ip_addr);
	ser_ip.sin_addr.s_addr = dst_ip_addr;
	
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	
	printf("client prepared OK\n");
	
	while(1)
	{
		sendto(sockfd, pSendBuf, strlen(pSendBuf), 0,
                      (const struct sockaddr *)&ser_ip, sizeof(ser_ip));
					  
		memset(rd_buf,0,1024);
		rev_size = recvfrom(sockfd, rd_buf, 1024, 0,
                        NULL, NULL);
						
						
		printf("client role : rev_size = %d, recv context: %s\n  ",rev_size,rd_buf);
		
		sleep(5);
		
		
	}

	
	return 0;
}




三、 UDP组播

 1、组播是Server端向局域网中的一个子网内加入了某个组播组的Client批量发送数据,组播的IP地址配置如下:

    224.0.0.0~224.0.0.255 为预留的组播地址(永久组地址),地址 224.0.0.0 保留不做分配,其它地址供路由协议使用;
    224.0.1.0~224.0.1.255 是公用组播地址,可以用于 Internet; 欲使用需申请。
   224.0.2.0~238.255.255.255 为用户可用的组播地址(临时组地址),全网范围内有效;
   239.0.0.0~239.255.255.255 为本地管理组播地址,仅在特定的本地范围内有效。

2、组播的实现,代码中也是尽可能的做了注释:

     组播Server的实现

#include <stdio.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>


#define SER_PORT  (8000)
#define CLI_PORT  (9000)

#define GROUP_IP ("239.0.0.2")
#define LOCAL_IP ("0.0.0.0")


int main(void)
{
	int sockfd = -1;
	struct sockaddr_in ser_addr,cli_addr;
	struct ip_mreq group_addr;
	char muticast_buf[1024] = {"muti caset data"};
	
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	
	/*第一步,绑定Server端的IP地址和端口号*/
	memset(&ser_addr,0,sizeof(ser_addr));
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_port = htons(SER_PORT);
	ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	
	bind(sockfd, (const struct sockaddr *)&ser_addr,sizeof(ser_addr));

	/*第二步,设置组播地址并指定发送组播数据*/
	memset(&group_addr,0,sizeof(group_addr));
	inet_pton(AF_INET,GROUP_IP,&group_addr.imr_multiaddr); //设置组播地址
	inet_pton(AF_INET,LOCAL_IP,&group_addr.imr_interface); //设置本地IP地址
											
	setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, &group_addr, sizeof(group_addr)); // 制定发送组播数据包
																					  //IP_MULTICAST_IF:指定发送组播数据的命令
																					  
	/*第三步,构造Client端的IP地址和端口号*/
	memset(&cli_addr,0,sizeof(cli_addr));
	cli_addr.sin_family = AF_INET;
	cli_addr.sin_port = htons(CLI_PORT); 
	inet_pton(AF_INET,GROUP_IP,&cli_addr.sin_addr.s_addr);	//注意:这里的组播客户端的地址就是组播地址
	
	printf("mutiast config finished ,then send muticast datas\n");
	/*第四步,向制定的组播地址发送数据*/
	while(1)
	{
		//调用sendto来向组播地址发送组播包
		sendto(sockfd, muticast_buf, strlen(muticast_buf), 0,(const struct sockaddr *)&cli_addr, sizeof(cli_addr));
		
		printf("muticast packet send ok\n");
		
		sleep(2);//2s发送一次
	}
	close(sockfd);
	return 0;
}




   组播Client的实现

#include <stdio.h>
#include <sys/types.h>         
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>


#define SER_PORT  (8000)
#define CLI_PORT  (9000)

#define GROUP_IP ("239.0.0.2")
#define LOCAL_IP ("0.0.0.0")


int main(void)
{
	int sockfd = -1;
	struct sockaddr_in cli_addr;
	struct ip_mreq group_addr;
	char recv_buf[1024] = {0};
	int recv_len = -1;
	
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	/*第一步,绑定本地IP地址结构*/
	memset(&cli_addr,0,sizeof(cli_addr));
	cli_addr.sin_family = AF_INET;
	cli_addr.sin_port = htons(CLI_PORT);
	inet_pton(AF_INET,LOCAL_IP,&cli_addr.sin_addr.s_addr);
	
	bind(sockfd, (const struct sockaddr *)&cli_addr,sizeof(cli_addr));
	
	/*第二步,设置组播地址并将client加入组播组*/
	memset(&group_addr,0,sizeof(group_addr));
	inet_pton(AF_INET,GROUP_IP,&group_addr.imr_multiaddr); //设置组播地址
	inet_pton(AF_INET,LOCAL_IP,&group_addr.imr_interface); //设置本地IP地址
											
	setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group_addr, sizeof(group_addr)); // 加入组包组
																					   //IP_ADD_MEMBERSHIP:加入组播组的命令
																					  	
	/*第三步,接受组播数据*/
	while(1)
	{
		memset(recv_buf,0,1024);
		recv_len = recvfrom(sockfd, recv_buf, 1024, 0,NULL, NULL); 
		
		if(recv_len > 0)
		{
			printf("recv_len = %d, recv_buf:%s\n",recv_len,recv_buf);
		}	
		
	}
	close(sockfd);
	return 0;
}









猜你喜欢

转载自blog.csdn.net/weixin_40204595/article/details/84447046
今日推荐