diff --git a/day3/qq2/qq3.c b/day3/qq2/qq3.c new file mode 100644 index 0000000..33a48df --- /dev/null +++ b/day3/qq2/qq3.c @@ -0,0 +1,123 @@ +// 群聊(组播-多播) +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* +* ./a.out port +*/ + +void *recv_task(void *arg); +void *send_task(void *arg); + +int bind_port; +char groupip[16] = ""; + +int main(int argc, char const *argv[]) +{ + if (argc < 3) + { + printf("usage: %s port groupip\n", argv[0]); + return -1; + } + + bind_port = atoi(argv[1]); + strcpy(groupip, argv[2]); // 多播组ip + + int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + if (sock_fd < 0) + { + perror("socket"); + return EXIT_FAILURE; // 1 + } + + // 绑定端口 + struct sockaddr_in bind_addr; + memset(&bind_addr, 0, sizeof(bind_addr)); + bind_addr.sin_family = AF_INET; + bind_addr.sin_port = htons(bind_port); + bind_addr.sin_addr.s_addr = htonl(INADDR_ANY); + bind(sock_fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); // 绑定文件描述符和地址端口 + + // 设置 socket 选项为多播(组号从命令行获取) + struct ip_mreq group_mreq; // 组消息请求结构体对象 + group_mreq.imr_multiaddr.s_addr = inet_addr(groupip); // 添加多播组的ip + group_mreq.imr_interface.s_addr = htonl(INADDR_ANY); // 当前主机的所有 ip 地址加入多播组中 + + int ret = setsockopt(sock_fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &group_mreq, sizeof(group_mreq)); + if (ret != 0) + { + perror("setsockopt"); + } + + pthread_t tid1, tid2; + pthread_create(&tid1, NULL, recv_task, &sock_fd); + pthread_create(&tid2, NULL, send_task, &sock_fd); + + pthread_join(tid2, NULL); + pthread_cancel(tid1); + pthread_join(tid1, NULL); + + printf("---over---\n"); + close(sock_fd); + + return 0; +} + +void *recv_task(void *arg) +{ + int sock_fd = *((int *)arg); + + while (1) + { + struct sockaddr_in data_addr; + socklen_t data_addr_len = sizeof(data_addr); + bzero(&data_addr, data_addr_len); + + char buf[128] = ""; + + ssize_t recv_len = recvfrom(sock_fd, buf, 128, 0, (struct sockaddr *)&data_addr, &data_addr_len); + if (recv_len > 0) + { + char ip[16] = ""; + inet_ntop(AF_INET, &data_addr.sin_addr.s_addr, ip, 16); + printf("%s(%d): %s\n", ip, ntohs(data_addr.sin_port), buf); + } + } +} + +void *send_task(void *arg) +{ + int sock_fd = *((int *)arg); + + while (1) + { + char buf[128] = ""; + if (fgets(buf, 128, stdin) != NULL) + { + buf[strlen(buf) - 1] = 0; + + struct sockaddr_in addr; + bzero(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(bind_port); + addr.sin_addr.s_addr = inet_addr(groupip); // 一定是多播地址 + + sendto(sock_fd, buf, strlen(buf) + 1, 0, (struct sockaddr *)&addr, sizeof(addr)); + if (strncmp(buf, "bye", 3) == 0) + { + break; + } + if (strncmp(buf, "clear", 5) == 0) + { + system("clear"); + } + } + } +} \ No newline at end of file