1、功能:实现一个组播聊天室,组播地址自己指定,任何人都可以加入,有成员加入时,会广播一条消息:加入成员的IP和端口加上加入了组播,退出组播的时候,也广播一条消息:退出成员的IP和端口加上退出了组播。同时实现发送和接收。
2、思路
(1)通过主函数传参,接收要加入的组播IP与端口
(2)通过if判断是否加入组播,并定义一个标识位flag
(3)创建一个子线程进行接收消息
(4)主进程进行发送消息
a.通过if判断是否加入了组播,
b.加入了组播就可以再次通过输入进行选择给谁发消息
c.没有加入就可以直接与其它人通信
3、代码实现
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>
#include<pthread.h>
int fd=-1;
//给他其人发送消息函数
void send_qita();
void *receive(void *arg)
{
struct sockaddr_in addr;
socklen_t addrlen;
char buf[100];
while(1)
{
bzero(buf, 100);
int s = recvfrom(fd, buf, 100, 0, (struct sockaddr*)&addr, &addrlen);
printf("群消息:%s",buf);
}
}
int main(int argc, char *argv[])
{
//创建套接字
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd == -1)
{
perror("socket");
exit(-1);
}
//设置组播属性
struct ip_mreq member;
member.imr_multiaddr.s_addr = inet_addr(argv[1]);
member.imr_interface.s_addr = INADDR_ANY;
socklen_t member_len = sizeof(member);
//设置组播ip
struct sockaddr_in addr;
addr.sin_port = htons(atoi(argv[2]));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ZBIP);
socklen_t addrlen = sizeof(addr);
//绑定自己的ip
struct sockaddr_in my_addr;
my_addr.sin_port = htons(atoi(argv[2]));
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
socklen_t my_addrlen = sizeof(my_addr);
//加入组播
int flag = 0;
printf("是否加入组播?输入y进入:\n");
if(getchar() == 'y')
{
flag = 1;
setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &member, member_len);
}
while(getchar() != '\n');
//绑定并创建接受子线程
bind(fd, (struct sockaddr *)&my_addr, my_addrlen);
pthread_t tid;
pthread_create(&tid, NULL, receive, NULL);
//发送消息
char buf[100];
snprintf(buf,100,"%s[%d]进入了组播\n","192.168.92.134",atoi(argv[2]));
sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&addr, addrlen);
usleep(100);
while(1)
{
printf("你要退出组播吗?输入y退出\n");
if(getchar() == 'y')
{
snprintf(buf,100,"%s[%d]进入了组播\n","192.168.92.134",atoi(argv[1]));
sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&addr, addrlen);
flag = 0;
usleep(100);
setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &member, member_len);
}
while(getchar() != '\n');
if(flag)
{
printf("你想要给组播发消息吗?(输入y给组播发消息)\n");
if(getchar() == 'y')
{
while(getchar() != '\n');
while(1)
{
printf("请输入你想要发送的消息(输入beybey结束本次会话):\n");
bzero(buf, 100);
fgets(buf, 100, stdin);
if(strcmp(buf, "beybey\n") == 0)
{
break;
}
sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)&addr, addrlen);
}
}
else
{
while(getchar() != '\n');
send_qita();
}
}
else
{
send_qita();
}
}
}
//给他其人发送消息函数
void send_qita()
{
char *send_buf = malloc(100);
char ip[20];
char port[10];
struct sockaddr_in send_addr;
send_addr.sin_family = AF_INET;
bzero(send_buf, 100);
bzero(ip, 20);
bzero(port, 10);
printf("请输入你想要发送消息对象的ip地址\n");
fgets(ip, 20, stdin);
int i = 10;
while(1)
{
if(ip[i] == '\n' || ip[i] == 0)
{
ip[i] = '\0';
break;
}
i++;
}
send_addr.sin_addr.s_addr = inet_addr(send_buf);
printf("请输入你想要发送消息对象的端口号\n");
fgets(port, 10, stdin);
i = 0;
while(1)
{
if(port[i] == '\n' || port[i] == 0)
{
port[i] = '\0';
break;
}
i++;
}
send_addr.sin_port = htons(atoi(port));
while(1)
{
printf("请输入你想要发送的消息(输入beybey结束本次会话):\n");
fgets(send_buf, 100, stdin);
int send_ret = send(fd, send_buf, 100, 0);
printf("send_tret = %d", send_ret);
if(strcmp(send_buf, "beybey\n") == 0)
{
break;
}
}
}