IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> socket udp单播和组播的简单封装 -> 正文阅读

[网络协议]socket udp单播和组播的简单封装

我封装了一个udp的接口,有些地方还需要改进,但基本满足大部分的需求。
#流程介绍

函数介绍

sockfd

#include <sys/socket.h>
sockfd = socket(int socket_family, int socket_type, int protocol);
sockfd:描述符。
socket_family, 即协议域,又称为协议族(family)。常用的协议族有,AF_INET(IPV4)、AF_INET6(IPV6)、AF_LOCAL(或称AF_UNIX,Unix域socket)、AF_ROUTE等等。协议族决定了socket的地址类型,在通信中必须采用对应的地址,如AF_INET决定了要用ipv4 地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址。
socket_type: 指定socket类型。常用的socket类型有,SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET等。
protocol:故名思意,就是指定协议。常用的协议有,IPPROTO_TCP、IPPTOTO_UDP、IPPROTO_SCTP、IPPROTO_TIPC等,它们分别对应TCP传输协议、UDP传输协议、STCP传输协议、TIPC传输协议。注意:并不是上面的type和protocol可以随意组合的,如SOCK_STREAM不可以跟IPPROTO_UDP组合。当protocol为0时,会自动选择type类型对应的默认协议。

inet_addr

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);
功能:用来将参数cp 所指的网络地址字符串转换成网络所使用的二进制数字。

htons

#include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);
功能:将主机的无符号短整形数转换成网络字节顺序

setsockopt

#include <sys/types.h>
#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
sockfd :标识一个套接口的描述字。
  level:选项定义的层次;目前仅支持SOL_SOCKET和IPPROTO_TCP层次。
  optname:需设置的选项。
  optval:指针,指向存放选项值的缓冲区。
  optlen:optval缓冲区的长度。

bind

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
*int bind(int sockfd, const struct sockaddr addr, socklen_t addrlen);

封装文件.h

/*************************************************************************
UDP接口文件
  @File Name: network_multicast.h
@Created Time: 2021年03月29日 星期一 
************************************************************************/
#ifndef _NETWORK_MULTICAST_H_
#define _NETWORK_MULTICAST_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#define DATASIZE (1024*10)


typedef struct user_recv_{
	int     code;
	char    data[DATASIZE];							/*接收到的数据*/
	int     lenght;							/*长度*/
	void*   user;							/*用户传入的参数*/
}UserRecv_S;

typedef enum networktype_{
	UNICAST,	//单播
	MULTICAST,	//组播
	SPECAST,	//特定网卡接受组播
}NetworkType_EN;

typedef struct os_netwoek{
	char ip[16];
	int port;
}Network_S ;

//typedef void* (*HandleData)(UserRecv_S*  recv_info);
typedef void* (*HandleData)(void*  recv_info);

/*网络初始化结构体*/
typedef struct os_networmulticast{
	NetworkType_EN		entype;					/*网络类型*/
	Network_S			stsrc_ip_info;			/*源地址*/
	Network_S			stdst_ip_info;			/*目的地址*/
	char				amcast_ip[16];			/*组播地址*/
	int                 nmcast_port;			/*组播端口*/
	HandleData			fnhandledata;				/*数据处理函数*/
	int					nfd;						/*socke描述符*/
	struct sockaddr_in	stmucast_addr;			/*组播发送sockaddr_in*/
	struct sockaddr_in	stunque_addr;				/*单播发送sockaddr_in*/
	int					nflags;					/*阻塞方式*/
	struct timeval		sttimeout;				/*超时时间*/
	int					nrecv_opt;				/*接受缓冲区*/
	int					nsend_opt;				/*发送缓冲区*/
	int					nread_size;             /*要接受的字节长度,不要超过DATASIZEt */
	UserRecv_S			stuser_recv_handle;
	int                 loopBack;               /* 是否开启本地回环 */
}NetworkMulticast_S;



/*组播初始化,初始化后会自动接受数据并处理
 *@network_info  传入传出参数,用于保存初始化网络数据
 *返回值: 成功:0    失败:-1
 * */
int os_networkmulticast_init( NetworkMulticast_S* stpnetwork_info);

/*组播发送数据
 *@data				发送的数据
 *@lenght			发送的长度
 *@network_info		初始化后的os_networkmulticast参数
 *返回值:			成功:发送的字节   失败:-1
 * */
int os_networkmulticast_send(const char *pdata, int nlenght, NetworkMulticast_S* stpnetwork_info);

/*单播发送数据
 *@data				发送的数据
 *@lenght			发送的长度
 *@ip				接受方的ip
 *@port				接受方的端口
 *返回值:			成功:发送的字节   失败:-1
 * */
int os_networkunque_ip_send(const char *pdata, int nlenght, NetworkMulticast_S* stpnetwork_info, char* pip, int nport);

/*单播发送数据
 *@data				发送的数据
 *@lenght			发送的长度
 *@network_info		初始化后的os_networkmulticast参数
 *返回值:			成功:发送的字节   失败:-1
 * */
int os_networkunque_send(const char *pdata, int nlenght, NetworkMulticast_S* stpnetwork_info);

/*组播退出
 *@network_info  初始化后的os_networkmulticast参数
 *返回值: 成功:0    失败:-1
 * */
int os_networkmulticast_exit( NetworkMulticast_S* stpnetwork_info);
#ifdef __cplusplus
}
#endif
#endif

封装文件.C

/*************************************************************************
  UDP接口文件
  @File Name: network_multicast.c
  @Created Time: 2021年03月29日 星期一 
 ************************************************************************/

#include"os_network_multicast.h"

static int os_network_socket(NetworkMulticast_S*  stpnetwork_info)
{
	int sockfd;
	if( NULL == stpnetwork_info )
	{
		return -3;
	}
	//创建套接字
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	struct sockaddr_in sock_addr, mucast_addr, unque_addr;
	memset(&sock_addr, 0, sizeof(sock_addr));
	memset(&mucast_addr, 0, sizeof(mucast_addr));
	memset(&unque_addr, 0, sizeof(unque_addr));
	sock_addr.sin_family = AF_INET;  

	if(stpnetwork_info->entype == UNICAST)
	{
		unque_addr.sin_family = AF_INET;
		sock_addr.sin_addr.s_addr = inet_addr(stpnetwork_info->stsrc_ip_info.ip);  //源IP地址
		sock_addr.sin_port = htons(stpnetwork_info->stsrc_ip_info.port);  //端口
		unque_addr.sin_addr.s_addr = inet_addr(stpnetwork_info->stdst_ip_info.ip);  //目的IP地址
		unque_addr.sin_port = htons(stpnetwork_info->stdst_ip_info.port);  //端口
		memcpy(&stpnetwork_info->stunque_addr, &unque_addr, sizeof(struct sockaddr_in));
	}
	else
	{
		mucast_addr.sin_family = AF_INET;
		sock_addr.sin_addr.s_addr = INADDR_ANY;//默认所有地址
		sock_addr.sin_port = htons(stpnetwork_info->stsrc_ip_info.port);  //端口
		mucast_addr.sin_addr.s_addr = inet_addr(stpnetwork_info->amcast_ip);  //具体的IP地址
		if( stpnetwork_info->nmcast_port <= 0)
		{
			mucast_addr.sin_port = htons(stpnetwork_info->stsrc_ip_info.port);  //端口
		}
		else
		{
			mucast_addr.sin_port = htons(stpnetwork_info->nmcast_port);  //端口
		}
		memcpy(&stpnetwork_info->stmucast_addr, &mucast_addr, sizeof(struct sockaddr_in));
	}
	/*设置超时时间*/
	if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &stpnetwork_info->sttimeout, sizeof(stpnetwork_info->sttimeout)) < 0)
	{
		perror("time out setting failed\n");
		goto error;
	}
	/*端口复用*/
	int reuse = 1;
	if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0)
	{
		perror("Setting SO_REUSEADDR error");
		goto error;
	}
	int ret = bind(sockfd, (struct sockaddr*)&sock_addr, sizeof(sock_addr));
	if(-1 == ret)
	{
		perror("bind:");
		goto error;
	}

	if(stpnetwork_info->entype == UNICAST)
	{
		stpnetwork_info->nfd =sockfd;
		return 0;
	}

	/*设置是否支持本地回环接收,1是0否*/
	int loopBack=stpnetwork_info->loopBack;
	ret = setsockopt(sockfd,IPPROTO_IP, IP_MULTICAST_LOOP, &loopBack, sizeof(loopBack));
	if(-1 == ret)
	{
		printf("setsockopt broadcaset error!!!\n");
		perror("setsockopt:");
		goto error;
	}
	/*设置缓冲区大小*/
	if (stpnetwork_info->nrecv_opt > 0)
	{
		if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &stpnetwork_info->nrecv_opt, sizeof(int)) < 0)
		{
			printf("setsockopt error=%d(%s)!!!\n", errno, strerror(errno));
			goto error;
		}
	}
	if (stpnetwork_info->nsend_opt > 0)
	{
		if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &stpnetwork_info->nrecv_opt, sizeof(int)) < 0)
		{
			printf("setsockopt error=%d(%s)!!!\n", errno, strerror(errno));
			goto error;
		}
	}
	/*加入多播组*/
	struct in_addr addr;
	memset(&addr, 0, sizeof(addr));
	if(stpnetwork_info->entype == MULTICAST)
	{
		addr.s_addr=INADDR_ANY;
	}
	else if(stpnetwork_info->entype == SPECAST)
	{
		addr.s_addr=inet_addr(stpnetwork_info->stsrc_ip_info.ip);
	}

	struct ip_mreq ipmr;
	ipmr.imr_interface.s_addr = addr.s_addr;

	ipmr.imr_multiaddr.s_addr = inet_addr(stpnetwork_info->amcast_ip);
	ret=setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,(const char*)&ipmr,sizeof(ipmr));
	if (ret < 0)
	{
		perror("setsockopt():IP_ADD_MEMBERSHIP");
		goto error;
	}
	/*此处指定组播数据的出口网卡,如果不设置则会根据路由表指定默认路由出口*/
	if(stpnetwork_info->entype == SPECAST)
	{
		if(-1 == setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr, sizeof(addr)))
		{
			printf("set error IP_MULTICAST_IF %s\n", stpnetwork_info->amcast_ip);
			perror("Setting IP_MULTICAST_IF error:");
			goto error;
		}
	}
	printf("socket success\n");
	stpnetwork_info->nfd =sockfd;
	return 0;
error:
	if (sockfd >= 0)
	{
		close(sockfd);
	}
	return -1;
}


int os_networkunque_send(const char *pdata, int nlenght, NetworkMulticast_S* pNetwork_info)
{
	int nsend_lenght=0, nret=0;

	if( NULL == pdata )
	{
		return -1;

	}

	if( 0 >= nlenght  )
	{
		return -2;

	}

	if( NULL == pNetwork_info )
	{
		return -3;
	}

	while( nsend_lenght < nlenght )
	{

		nret = sendto(pNetwork_info->nfd, pdata + nsend_lenght, nlenght-nsend_lenght, pNetwork_info->nflags, (struct sockaddr *)&(pNetwork_info->stunque_addr), sizeof(pNetwork_info->stunque_addr));
		if(nret<0)
		{
			printf("os_networkunque_send error nRet[%d]\n",nret);
			break;
		}
		if(nret == -1)
		{
			printf("send fail\n");
			return -1;
		}
		nsend_lenght += nret;
	}
	return nsend_lenght;
}

int os_networkunque_ip_send(const char *pdata, int nlenght, NetworkMulticast_S* pNetwork_info, char* ip, int port)
{
	if( NULL == pdata )
	{
		return -1;

	}

	if( 0 >= nlenght  )
	{
		return -2;

	}

	if( NULL == pNetwork_info )
	{
		return -3;
	}

	if( NULL == ip )
	{
		return -4;
	}

	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(port); 
	seraddr.sin_addr.s_addr = inet_addr(ip);
	return sendto(pNetwork_info->nfd, pdata, nlenght, pNetwork_info->nflags, (struct sockaddr *)&(seraddr), sizeof(seraddr)) ;     

	int nsend_lenght=0, nret=0;
	if(pdata == NULL)
		return -1;
	if(nlenght <=0)
		return -2;
	while( nsend_lenght < nlenght )
	{
		nret = sendto(pNetwork_info->nfd, pdata + nsend_lenght, nlenght-nsend_lenght, pNetwork_info->nflags, (struct sockaddr *)&(seraddr), sizeof(seraddr)) ;
		nsend_lenght += nret;
		if(nret == -1)
		{
			printf("send fail\n");
			return -1;
		}
	}
	return nsend_lenght;
}
int os_networkmulticast_send(const char *pdata, int nlenght, NetworkMulticast_S* pNetwork_info)
{
	int nsend_lenght=0, nret=0;

	if(pdata == NULL)
	{
		return -1;
	}

	if(nlenght <=0)
	{
		return -2;
	}

	if( NULL == pNetwork_info )
	{
		return -3;
	}
	while( nsend_lenght < nlenght )
	{
		nret =sendto(pNetwork_info->nfd, pdata + nsend_lenght, nlenght-nsend_lenght, pNetwork_info->nflags, (struct sockaddr *)&(pNetwork_info->stmucast_addr), sizeof(pNetwork_info->stmucast_addr)) ;     
		nsend_lenght+=nret;
		if(nret == -1)
		{
			printf("send fail\n");
			perror("send:");
			return -1;
		}
	}

	return nsend_lenght;

}

void* os_networkmulticast_recv(void* network_info1)
{
	int nrecv_size = 0;
	NetworkMulticast_S* stpnetwork_info = (NetworkMulticast_S* )network_info1;

	if( stpnetwork_info == NULL)
	{
		return NULL;
	}
	if( stpnetwork_info->fnhandledata == NULL)
	{
		return NULL;

	}
	/*数据大于DATASIZE 分段发送*/
	if( stpnetwork_info->nread_size <= 0 )
	{
		nrecv_size = DATASIZE;
	}
	else if( stpnetwork_info->nread_size >= DATASIZE )
	{
		nrecv_size = DATASIZE;
	}
	else
	{
		nrecv_size =  stpnetwork_info->nread_size;
	}

	while (1)
	{
		int datalenght=0;
		char data[DATASIZE];
		struct sockaddr_in sock_addr;
		memset(data, 0, DATASIZE); 
		memset(&sock_addr, 0, sizeof(sock_addr));
		int addr_length=sizeof(sock_addr);
		datalenght=recvfrom(stpnetwork_info->nfd, data, nrecv_size, 0, (struct sockaddr *)&sock_addr,(socklen_t*)&addr_length);
		if(datalenght < 0)
		{
			break;
		}
		memcpy(stpnetwork_info->stuser_recv_handle.data, data, datalenght);
		stpnetwork_info->stuser_recv_handle.lenght = datalenght;
		//回调处理数据,可修改成异步
		stpnetwork_info->fnhandledata( &stpnetwork_info->stuser_recv_handle );
	} 
	return NULL;
}
int os_networkmulticast_init(NetworkMulticast_S* stpnetwork_info)
{
	os_network_socket(stpnetwork_info);
	if( NULL == stpnetwork_info->fnhandledata)
	{
		return 0;
	}
	pthread_t tid;
 
	pthread_attr_t attr;			/*通过线程属性来设置游离态*/
	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr,	PTHREAD_CREATE_DETACHED);
	return pthread_create(&tid, &attr, os_networkmulticast_recv, (void*)stpnetwork_info);
	
}
int os_networkmulticast_exit( NetworkMulticast_S* stpnetwork_info )
{
	if(close(stpnetwork_info->nfd) < 0) 
	{
		printf("closesocket failed with error \n");
		return 1;
	}
	return 0;
}

测试文件

/*************************************************************************
@File Name: test.c
@Created Time: 2021年04月08日 星期四 15时19分31秒
************************************************************************/
#include"os_network_multicast.h"
/*接口测试*/
NetworkMulticast_S network_info;

void* data_handle(void* recv_info1)
{
	    UserRecv_S* recv_info =(UserRecv_S*)recv_info1;
		printf("数据:");
		int i=0;
        while(i < recv_info->lenght)
			printf("%x ",recv_info->data[i++]);
		printf("\n");
	//	os_networkmulticast_send(recv_info->data, strlen(recv_info->data), &network_info);
	//	os_networkunque_send(recv_info->data, strlen(recv_info->data), &network_info);
	//	os_networkunque_ip_send(recv_info->data, strlen(recv_info->data), &network_info,"172.16.18.207", 8803);

}
int main()
{
	memset(&network_info, 0 ,sizeof(network_info));
	
	network_info.entype=MULTICAST; //开启组播
	//network_info.entype=UNICAST;  // 开启单播
	//strcpy(network_info.stsrc_ip_info.ip, "172.16.18.71");
	network_info.stsrc_ip_info.port=9099;
	
	//strcpy(network_info.stdst_ip_info.ip,"172.16.18.244");
	//network_info.stdst_ip_info.port=8803;
	
	/*传入接受到数据的回调处理*/
	network_info.fnhandledata=data_handle;
	strcpy(network_info.amcast_ip,"224.0.0.5");

	/*初始化网络*/
	os_networkmulticast_init(&network_info);

	char aaaa[64] = {0};
	


	//os_networkmulticast_send("1234567890", 10, &network_info);
	while(1)
	{
		scanf("%s",aaaa);


	os_networkmulticast_send(aaaa,strlen(aaaa),&network_info);
	}
	return 0;
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-10-27 13:09:19  更:2021-10-27 13:10:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:25:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码