Unix下UDP广播群聊例程

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>

#include <signal.h>
#include <sys/ioctl.h>
#include <net/if.h>

#include <pthread.h>

// Unix下UDP广播群聊例程
// 编译: gcc group_talk.c -lpthread

#define BROCAST_PORT 6024
//#define RECEIVE_PORT 6024
#define THREAD_RUNNING 1
#define THREAD_STOP 0
int brocast_sock = -1;  
int receive_sock = -1;
int thrd_status = THREAD_RUNNING;
pthread_t thread_id;

struct msg_t
{
	unsigned int msg_id;
	struct in_addr src_ip;
	struct in_addr dst_ip;
	char nename[128];
	char message[1024];
};


char conn_agent_ip[128];
char init_agent_ip[128];
char find_agent_ip[128];
#define AGENT_PORT 6024
char local_device_name[128] = "eth0";
char local_device_ip[128] = "";
char local_nename[128] = "";
char old_device_ip[128] = "";

#define SA struct sockaddr
#define LISTENQ 5


#define MAX_IFS 64
char * get_device_ip(char * device_name)
{
	struct ifreq *ifr, *ifend;
	struct ifreq ifreq;
	struct ifconf ifc;
	struct ifreq ifs[MAX_IFS];
	static char ip_addr[128];
	int SockFD;
	SockFD = socket(AF_INET, SOCK_DGRAM, 0);
	ifc.ifc_len = sizeof(ifs);
	ifc.ifc_req = ifs;
	if (ioctl(SockFD, SIOCGIFCONF, &ifc) < 0) {
		printf("ioctl(SIOCGIFCONF): %m\n");
		close(SockFD);
		return NULL;
	}
	ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
	for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
		if (ifr->ifr_addr.sa_family == AF_INET) {
			strncpy(ifreq.ifr_name, ifr->ifr_name,sizeof(ifreq.ifr_name));
			if (ioctl (SockFD, SIOCGIFHWADDR, &ifreq) < 0) {
				printf("SIOCGIFHWADDR(%s): %m\n", ifreq.ifr_name);
				close(SockFD);
				return NULL;
			}
			printf("Device %s \n", ifreq.ifr_name);
			if (strcmp(device_name, ifreq.ifr_name)==0)
			{
				printf("Get [%s] IP [%s]\n", device_name, inet_ntoa( ( (struct sockaddr_in *)  &ifr->ifr_addr)->sin_addr));
				sprintf(ip_addr, "%s", inet_ntoa( ( (struct sockaddr_in *)  &ifr->ifr_addr)->sin_addr));

				close(SockFD);
				return ip_addr;
			}
		}
	}
	close(SockFD);
	memset(ip_addr, 0, sizeof(ip_addr));
	return ip_addr;
}

int brocast_msg(char * msg, int msg_len)
{
//	printf("brocast_msg(len:%d)\n", msg_len);

	struct sockaddr_in addrto;
	bzero(&addrto, sizeof(struct sockaddr_in));
	addrto.sin_family=AF_INET;
	addrto.sin_addr.s_addr=htonl(INADDR_BROADCAST);
	addrto.sin_port=htons(BROCAST_PORT);
	int ret;
	int len = sizeof(struct sockaddr_in);
	int i;

	ret=sendto(brocast_sock, msg, msg_len, 0, (struct sockaddr*)&addrto, len);  
	if(ret<0)
	{
		printf("brocast_msg: send error[%d]\n", ret);  
		return -1;
	}
	else  
	{
//		printf("brocast_msg: sent message OK\n");    
	}

	return 0;
}


int hello()
{
	printf("hello()\n");

	struct msg_t msg;
	msg.msg_id = 1;
	inet_pton(AF_INET, local_device_ip, (void *)&msg.src_ip);
	inet_pton(AF_INET, "0.0.0.0"      , (void *)&msg.dst_ip);
	snprintf(msg.nename, sizeof(msg.nename), "%s", local_nename);
	snprintf(msg.message, sizeof(msg.message), "hello.");
	brocast_msg((char *)&msg, sizeof(msg));

	return 0;
}

int goodbye()
{
	struct msg_t msg;
	msg.msg_id = 1;
	inet_pton(AF_INET, local_device_ip, (void *)&msg.src_ip);
	inet_pton(AF_INET, "0.0.0.0"      , (void *)&msg.dst_ip);
	snprintf(msg.nename, sizeof(msg.nename), "%s", local_nename);
	snprintf(msg.message, sizeof(msg.message), "goodbye.");
	brocast_msg((char *)&msg, sizeof(msg));

	return 0;
}

void *thrd_receive_msg(void *arg)
{

	// 设置其他线程可以cancel掉此线程
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);

	int len = sizeof(struct sockaddr_in);  
	struct msg_t rec_msg;

	while(thrd_status == THREAD_RUNNING)  
	{
		int ret;
		struct sockaddr_in from;  
		bzero(&from, sizeof(struct sockaddr_in));  
		from.sin_family = AF_INET;  
		from.sin_addr.s_addr = htonl(INADDR_ANY);  
		from.sin_port = htons(BROCAST_PORT); 

		fd_set fdsr;//文件描述符集
		int sel;
		struct timeval tv;
		FD_ZERO(&fdsr);
		FD_SET(receive_sock, &fdsr);//加入描述符集
		tv.tv_sec = 1;
		tv.tv_usec = 0;
		sel = select(receive_sock + 1, &fdsr, NULL, NULL, &tv);
		if (sel < 0) {
			printf("_recv_from: select error![%d:%s]\n", errno, strerror(errno));
			//continue;
		}
		else if (sel == 0)
		{
		//	printf("recv_from: time out![%d:%s]\n", errno, strerror(errno));
		}
		else
		{
			bzero(&rec_msg, sizeof(rec_msg));  
			ret=recvfrom(receive_sock, &rec_msg, sizeof(rec_msg), 0, (struct sockaddr*)&from,(socklen_t*)&len);  
			if(ret<=0)  
			{  
				printf("read error....\n");  
			}
			else  
			{
				if (rec_msg.msg_id == 0)
				{
					inet_ntop(AF_INET, (void *)&rec_msg.src_ip, find_agent_ip, 16);
					printf("main: Find agent ip=[%s].\n", find_agent_ip);
				}
				else if(rec_msg.msg_id == 1)
				{
					char src_ip[128],dst_ip[128];
					inet_ntop(AF_INET, (void *)&rec_msg.src_ip, src_ip, 16);
					inet_ntop(AF_INET, (void *)&rec_msg.dst_ip, dst_ip, 16);
					if (strcmp(src_ip, local_device_ip))
					printf("%s: %s\n", rec_msg.nename, rec_msg.message);
				}
			}
		}
		sleep(1);  
	}
	printf("Thread is exiting.\n");
	pthread_exit(NULL);
}

void signal_handler(int sig)
{
//	printf("signal_handler()\n");
	thrd_status = THREAD_STOP;

	goodbye();
	close(brocast_sock);
	close(receive_sock);
	exit(0);
	return;
}

int init(int argc, char * argv[])
{
	// 解析参数
	if (argc == 3)
	{
		sprintf(local_nename, "%s", argv[1]);
		sprintf(local_device_name,  argv[2]);
	}
	else if (argc == 2)
	{
		sprintf(local_nename, "%s", argv[1]);
		sprintf(local_device_name, "eth0");
	}
	else
	{
		sprintf(local_device_name, "eth0");
		sprintf(local_nename, "%s", get_device_ip(local_device_name));
	}
	sprintf(local_device_ip, "%s", get_device_ip(local_device_name));
	printf("!\n");
	if (strlen(local_device_ip) < 1)
	{
		printf("get device ip error!\n", local_device_name);
		exit(0);
	}
	printf("init: nename[%s] device name = [%s]   device ip = [%s]\n", local_nename, local_device_name, local_device_ip);

	// 设置信号
	signal(SIGTERM, signal_handler);
	signal(SIGINT, signal_handler);

	// 设置网络
	// 绑定地址
	struct sockaddr_in addrto;  
	bzero(&addrto, sizeof(struct sockaddr_in));  
	addrto.sin_family = AF_INET;
	addrto.sin_addr.s_addr = htonl(INADDR_ANY);  
	addrto.sin_port = htons(BROCAST_PORT);  

	if ((receive_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)   
	{
		printf("init: socket error\n");   
		exit(0);
	}
	const int opt = 1;  
	//设置该套接字为广播类型,  
	int nb = 0;  
	nb = setsockopt(receive_sock, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));  
	if(nb == -1)  
	{
		printf("init: set socket error...\n");
		close(receive_sock);
		exit(0); 
	}  
	if(bind(receive_sock,(struct sockaddr *)&(addrto), sizeof(struct sockaddr_in)) == -1)   
	{     
		printf("init: bind error...\n");
		close(receive_sock);
		exit(0);
	}

	if ((brocast_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)   
	{     
		printf("socket error\n");   
		exit(0);
	}
	//设置该套接字为广播类型,  
	nb = setsockopt(brocast_sock, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));  
	if(nb == -1)  
	{
		printf("set socket error...\n");
		close(brocast_sock);
		exit(0);
	}  
	// 创建线程,每个线程号返回给thread,每个线程的入口函数均为thrd_brocast_ip
	if (pthread_create(&thread_id,NULL,thrd_receive_msg,NULL)!=0)
	{
		printf("Create thread error!\n");
		exit(0);
	}
	else
	{
		printf("Create thread success!\n");
	}
	printf("init: Init complete!\n");
}

int main( int argc, char ** argv)
{
	init(argc, argv);

	if (hello())
	{
		printf("hello fail!\n");
		return -1;
	}

	char buf[2048];
	int len;
	struct msg_t brc_msg;
	while(thrd_status == THREAD_RUNNING)
	{
		bzero((void *)buf, sizeof(buf));  
		scanf("%s", buf);
		len = strlen(buf);
		
		if (len >= 1024)
		{
			printf("message too long\n");
			continue;
		}
		brc_msg.msg_id = 1;
		inet_pton(AF_INET, local_device_ip, (void *)&brc_msg.src_ip);
		inet_pton(AF_INET, "0.0.0.0"      , (void *)&brc_msg.dst_ip);
		snprintf(brc_msg.nename, sizeof(brc_msg.nename), "%s", local_nename);
		snprintf(brc_msg.message, sizeof(brc_msg.message), "%s", buf);
		brocast_msg((char *)&brc_msg, sizeof(brc_msg));
	}

	printf("Program is exiting.\n");
	close(brocast_sock);
	close(receive_sock);
	return 0;
}

转载于:https://my.oschina.net/u/1264314/blog/160980

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值