UDP 广播与组播

代码1:服务器端

#include "common.h"
int main()
{
	int fd;
	struct sockaddr_in caddr;
	char recvbuf[1024];
	char sendbuf[1024];
	int set = 1;
	int i=0;
	int addrLen = sizeof(caddr);
	//接收数据
	if((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1){
		printf("socket fail\n");
		return 0;
	}
	setsockopt(fd, SOL_SOCKET,SO_REUSEADDR, &set, sizeof(int));
	memset(&caddr, 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;
	}
	while(1)
	{
		
		int recvbytes = recvfrom(fd, recvbuf, 1024, 0,(struct sockaddr *)&caddr, &addrLen);
		printf("recv:%s\n",recvbuf);
		i++;
		//if(i==2)break;
	}

	printf("please input ...\n");
	scanf("%s",sendbuf);
	sendto(fd,sendbuf, 1024, 0,(struct sockaddr *)&caddr, sizeof(struct sockaddr));

}

代码2:客户端

#include "common.h"

int main()
{
	int fd;
	int optval = 1;//这个值一定要设置,否则可能导致sendto()失败
	struct sockaddr_in saddr;
	int sendBytes;
	char sendbuf[1024];
	char recvbuf[1024];
	int addrLen = sizeof(saddr);

	if((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){
		printf("socket fail\n");
		return ;
	}
	setsockopt(fd, SOL_SOCKET, SO_BROADCAST | SO_REUSEADDR, &optval, sizeof(int));//允许发送广播数据包,允许重用本地地址
	memset(&saddr, 0, sizeof(struct sockaddr_in));
	saddr.sin_family = AF_INET;
	saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	saddr.sin_port = htons(8080);
	
	while(1)
	{
		printf("please input ...\n");
		scanf("%s",sendbuf);
		if((sendBytes = sendto(fd, sendbuf, 1024, 0,(struct sockaddr *)&saddr, sizeof(struct sockaddr))) == -1)
		{
			printf("sendto model fail, errno=%d\n", errno);
			return ;
		}
		printf("send meg success...\n\n");

	}
	/*while(1)
	{

		recvfrom(fd, recvbuf, 1024, 0,(struct sockaddr *)&saddr, &addrLen);
		printf("recvbuf:%s\n",recvbuf);

	}*/

}

结果:

UDP 广播与组播_第1张图片

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

UDP 广播与组播_第2张图片

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

 

 

组播:

服务器端:

#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,暂且不清楚两者区别。

你可能感兴趣的:(C基础)