我封装了一个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;
}