UDP 广播与组播

代码1:服务器端

#include "../common.h"
int main()
{
	int serFd;
	struct sockaddr_in serAddr,cliAddr;
    int ret = 0;
	char recvbuf[1024];
	char sendbuf[1024];
	int set = 1;
	int addrLen = sizeof(sockaddr_in);
	//接收数据
	if((serFd = socket(PF_INET, SOCK_DGRAM, 0)) == -1){
		printf("socket fail\n");
		return 0;
	}
	setsockopt(serFd, SOL_SOCKET,SO_REUSEADDR, &set, sizeof(int));
	memset(&serAddr, 0, sizeof(struct sockaddr_in));
	serAddr.sin_family = AF_INET;
	serAddr.sin_port = htons(8888);
	serAddr.sin_addr.s_addr = INADDR_ANY;
	// 必须绑定,否则无法监听
	if(bind(serFd, (struct sockaddr *)&serAddr, sizeof(struct sockaddr)) == -1)
    {
		printf("bind fail\n");
		return 0;
	}
    printf("bind port:%d",8888);
	while(1)
	{
		ret = recvfrom(serFd, recvbuf, 1024, 0,(struct sockaddr *)&cliAddr, (socklen_t*)&addrLen);
        if(ret < 0)
        {
            break;
        }
		printf("recv from client(IP:%s port:%d):%s (ret = %d)\n",inet_ntoa(cliAddr.sin_addr),htons(cliAddr.sin_port),recvbuf,ret);
        sprintf(sendbuf,"I'm server");
        ret = sendto(serFd,sendbuf, strlen(sendbuf) + 1, 0,(struct sockaddr *)&cliAddr, sizeof(struct sockaddr));
        if(ret < 0)
        {
            break;
        }
        else
        {
            printf("send to client success ...\n\n");
        }  
		sleep(1);      
	}
    close(serFd);
}

代码2:客户端

#include "../common.h"
 
int main()
{
	int cliFd;
	int optval = 1;//这个值一定要设置,否则可能导致sendto()失败
	struct sockaddr_in serAddr;
	int ret = -1;
	char sendbuf[1024];
	char recvbuf[1024];
	int addrLen = sizeof(sockaddr_in);
 
	if((cliFd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
    {
		printf("socket fail\n");
		return 0;
	}
	setsockopt(cliFd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &optval, sizeof(int));//允许发送广播数据包,允许重用本地地址
	memset(&serAddr, 0, sizeof(struct sockaddr_in));
	serAddr.sin_family = AF_INET;
	serAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	serAddr.sin_port = htons(8888);
	
	while(1)
	{
        sprintf(sendbuf,"I'm client");
		if((ret = sendto(cliFd, sendbuf, strlen(sendbuf) + 1, 0,(struct sockaddr *)&serAddr, sizeof(struct sockaddr))) == -1)
		{
            char *errorMsg = strerror(errno);
			printf("sendto server fail:%s\n", errorMsg);
			return 0;
		}
        else
        {
            printf("send to server success ...\n");
        }

        ret = recvfrom(cliFd, recvbuf, 1024, 0,(struct sockaddr *)&serAddr, (socklen_t*)&addrLen);
        if(ret < 0)
        {
            break;
        }
        else
        {
            printf("recv from server:%s (ret = %d)\n\n",recvbuf,ret);
        }
		sleep(1);
	}
    close(cliFd);
}

结果:

如果把客户端的127.0.0.1改为255.255.255.255,结果为:

广播成功,所有的服务器均能收到

 

 

组播:

服务器端:

#include "common.h"

int fd;
struct sockaddr_in caddr,recvaddr;
int addrLen ;


void *thread(void *argv)
{
	char recvbuf[1024];
	while(1)
	{
		recvfrom(fd, recvbuf, 1024, 0,(struct sockaddr *)&recvaddr, &addrLen);
		printf("recv:%s\n",recvbuf);
	}
}


int main()
{
	char sendbuf[1024];
	int set = 1;
	int i=0;
	addrLen = sizeof(caddr);
	int sendBytes;
	//接收数据
	if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1){
		printf("socket fail\n");
		return 0;
	}
	
	memset(&caddr, 0, sizeof(struct sockaddr_in));
	memset(&recvaddr, 0, sizeof(struct sockaddr_in));

	caddr.sin_family = AF_INET;
	caddr.sin_port = htons(8080);
	caddr.sin_addr.s_addr = INADDR_ANY;
	// 绑定监听
	if(bind(fd, (struct sockaddr *)&caddr, sizeof(struct sockaddr)) == -1)
	{
		printf("bind fail\n");
		return 0;
	}

	int loop = 1;
	/*去掉以下4行,将不会收到客户端消息(移出了多播组)*/
	struct ip_mreq mreq;
	mreq.imr_multiaddr.s_addr = inet_addr("224.0.0.88");//多播地址
	mreq.imr_interface.s_addr = htonl(INADDR_ANY);
	setsockopt(fd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(struct ip_mreq));//加入多播组
	setsockopt(fd,SOL_SOCKET,SO_REUSEADDR, &set, sizeof(int));//端口复用
	setsockopt(fd,IPPROTO_IP, IP_MULTICAST_LOOP, &loop,sizeof (loop));//允许环回

	pthread_t pthid;
	pthread_create(&pthid, NULL, thread, NULL);

	while(1)
	{
		printf("input ... \n");
		scanf("%s",sendbuf);
		if((sendBytes = sendto(fd, sendbuf, 1024, 0,(struct sockaddr *)&recvaddr, sizeof(struct sockaddr))) == -1)//发送给客户端
		{
			printf("sendto model fail, errno=%d\n", errno);
			return ;
		}			

	}

}

客户端:

#include "common.h"

int fd;
struct sockaddr_in sendaddr,recvaddr;
int addrLen;

void *thread(void *argv)
{
	char recvbuf[1024];
	while(1)
	{
		printf("------------------\n");
		int ret = recvfrom(fd, recvbuf, 1024, 0,(struct sockaddr *)&recvaddr, &addrLen);
		if(ret<0)
		{
			perror("recvfrom");
			return 0;
		}		
		printf("recv:%s\n",recvbuf);
	}
}


int main()
{
	addrLen = sizeof(sendaddr);
	int optval = 1;
	int sendBytes;
	char sendbuf[1024];
	
	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
		printf("socket fail\n");
		return ;
	}

	memset(&sendaddr, 0, sizeof(struct sockaddr_in));
	memset(&recvaddr, 0, sizeof(struct sockaddr_in));

	setsockopt(fd,SOL_SOCKET,SO_REUSEADDR, &optval, sizeof(int));

	sendaddr.sin_family = AF_INET;
	sendaddr.sin_addr.s_addr = inet_addr("224.0.0.88"); //指定发送的多播组
	sendaddr.sin_port = htons(8080);  //指定发送到哪个端口

	pthread_t pthid;
	pthread_create(&pthid, NULL, thread, NULL);

	while(1)
	{
		printf("please input ...\n");
		scanf("%s",sendbuf);
		if((sendBytes = sendto(fd, sendbuf, 1024, 0,(struct sockaddr *)&sendaddr, sizeof(struct sockaddr))) == -1)
		{
			printf("sendto model fail, errno=%d\n", errno);
			return 0;
		}
		//printf("send meg success...\n\n");

	}

}

结果不再展示

 

mark:

setsockopt(fd, SOL_SOCKET,SO_REUSEADDR, &set, sizeof(int));

设置端口复用要在socket之后紧跟。在bind之后再设置没作用,仍会出现bind失败的情况。

创建套接字中的PF_INET实际也可换为AF_INET,暂且不清楚两者区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值