嵌入式学习——3——UDP ChatRoom

#include "../header.h"

#define MAX 1024

#define S_IP "192.168.125.174"
#define S_PORT 8888

typedef struct user_info {
    union {
        char name[20];
        int len;
    };
    struct sockaddr_in user_addr;
    struct user_info *next;
} userInfo, *userinfo_p;

// 消息类型
typedef struct Chat_info {
    char type[4]; // 字符 'LOGN'登录  'CHAT'聊天   'EXIT'退出
    char username[20];
    char message[1024];
} msg, *msg_p;

userinfo_p user_head; // list 头
int server_fd = -1;

// UDP 相关
int UDP_Chat_ROOM();
// 初始化链表,存储用户信息
userinfo_p init_user_info_list();
// 添加用户信息
int add_user(userinfo_p cla);
int delete_user(userinfo_p cla);
int list_user(msg_p sendmessages);

msg_p getChatMessage(char *type, char *message, char *name);
int main(int argc, char const *argv[]) {

    user_head = init_user_info_list();
    UDP_Chat_ROOM();

    return 0;
}
int UDP_Chat_ROOM() {
    server_fd = socket(AF_INET, SOCK_DGRAM, 0);
    int reuse = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse,
                   sizeof(reuse)) == -1) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    if (server_fd == -1) {
        perror("socket");
        return -1;
    }

    struct sockaddr_in ser_address = {0};
    ser_address.sin_family = AF_INET;
    ser_address.sin_port = htons(S_PORT);
    ser_address.sin_addr.s_addr = inet_addr(S_IP);
    if (bind(server_fd, (struct sockaddr *)&ser_address, sizeof(ser_address)) ==
        -1) {
        perror("bind");
        return -1;
    }

    msg recvmessages = {0};

    struct pollfd fds[2] = {0};
    fds[0].fd = 0;
    fds[0].events = POLLIN;
    fds[1].fd = server_fd;
    fds[1].events = POLLIN;

    while (1) {
        int resp = poll(fds, 2, -1);
        if (resp == -1) {
            perror("poll");
            return -1;
        } else if (resp == 0) {
            printf("timeout\n");
        }
        if (fds[0].revents == POLLIN) {
            char send_buf[1024];
            bzero(send_buf, sizeof(send_buf));
            fgets(send_buf, sizeof(send_buf), stdin);
            if (strlen(send_buf) > 1) {
                send_buf[strlen(send_buf) - 1] = '\0';
            }
            msg_p sendmessages;
            sendmessages = getChatMessage("CHAT", send_buf, "***system***");
            list_user(sendmessages);
        }
        if (fds[1].revents == POLLIN) {
            struct sockaddr_in rev_address = {0};
            socklen_t rev_len = sizeof(rev_address);
            recvfrom(server_fd, &recvmessages, sizeof(recvmessages), 0,
                     (struct sockaddr *)&rev_address, &rev_len);
            if (strncmp(recvmessages.type, "LOGN", 4) == 0) {
                // 登陆消息
                printf("*********%s进入聊天室(当前人数%d)*********\n",
                       recvmessages.username, user_head->len);
                userInfo user;
                strcpy(user.name, recvmessages.username);
                user.user_addr = rev_address;
                add_user(&user);
                msg_p sendmessages;
                sendmessages =
                    getChatMessage("LOGN", "进入聊天室", recvmessages.username);
                list_user(sendmessages);
            } else if (strncmp(recvmessages.type, "CHAT", 4) == 0) {
                // 普通消息
                printf("%s:chat\n", recvmessages.username);
                msg_p sendmessages;
                sendmessages = getChatMessage("CHAT", recvmessages.message,
                                              recvmessages.username);
                list_user(sendmessages);
            } else {
                // 某人退出聊天室
                printf("*********%s退出聊天室(当前人数%d)*********\n",
                       recvmessages.username, user_head->len);
                msg_p sendmessages;
                sendmessages =
                    getChatMessage("EXIT", "退出聊天室", recvmessages.username);
                list_user(sendmessages);
                userInfo user;
                strcpy(user.name, recvmessages.username);
                user.user_addr = rev_address;
                delete_user(&user);
            }
        }
    }

    close(server_fd);
}
/*↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓数据链表相关操作↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
// 初始化链表
userinfo_p init_user_info_list() {
    struct sockaddr_in user_addr = {0};
    userinfo_p us_head = (userinfo_p)malloc(sizeof(userInfo));
    if (us_head == NULL) {
        printf("申请失败");
        return 0;
    }
    us_head->len = 0;
    bzero(&(us_head->user_addr), sizeof(us_head->user_addr));
    return us_head;
}
// 链表添加数据
int add_user(userinfo_p cla) {
    if (cla == NULL || user_head->len >= MAX) {
        printf("添加失败\n");
        return 0;
    }
    userinfo_p user = (userinfo_p)malloc(sizeof(userInfo));
    strcpy(user->name, cla->name);
    user->user_addr = cla->user_addr;
    user->next = user_head->next;
    user_head->next = user;
    user_head->len++;

    return 0;
}
// 链表删除数据
int delete_user(userinfo_p cla) {
    if (cla == NULL || user_head->len == 0) {
        printf("删除失败\n");
        return 0;
    }
    if (user_head->next == NULL) {
        printf("删除失败\n");
        return 0;
    }
    userinfo_p user = user_head;
    while (1) {
        if (user->next == NULL) {
            break;
        }
        userinfo_p user_next = user->next; // 记录下一条
        if (strcmp(user_next->name, cla->name) == 0) {
            // 相同数据,删除该条
            user->next = user_next->next;
            free(user_next);
            user_head->len--;
            return 0;
        } else {
            // 不相同数据,继续遍历
            user = user->next;
        }
    }
    return 0;
}
// 链表遍历
int list_user(msg_p sendmessages) {
    userinfo_p user = user_head->next;
    while (1) {
        if (user_head->len == 0 || user_head->next == NULL) {
            printf("遍历失败\n");
            return 0;
        }
        // 遍历发给所有人
        if (sendto(server_fd, sendmessages, sizeof(msg), 0,
                   (struct sockaddr *)&(user->user_addr),
                   sizeof(struct sockaddr_in)) == -1) {
            perror("sendto");
            return -1;
        }
        if (user->next == NULL) {
            break;
        }
        user = user->next;
    }
    return 0;
}
/*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑数据链表相关操作↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/

msg_p getChatMessage(char *type, char *message, char *name) {
    msg nmsg = {0};
    strcpy(nmsg.type, type);
    strcpy(nmsg.username, name);
    strcpy(nmsg.message, message);
    msg_p nmsgs = &nmsg;
    return nmsgs;
}
#include "../header.h"

#define C_IP "192.168.125.174"
#define C_PORT 6677
typedef struct Chat_info {
    char type[4]; //  LOGN 登录  CHAT 聊天   EXIT 退出
    char username[20];
    char message[1024];
} msg, *msg_p;
char name[20] = "";

msg_p getChatMessage(char *type, char *message);

int main(int argc, char const *argv[]) {

    int cli_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (cli_fd == -1) {
        perror("socket");
        return -1;
    }
    int reuse = 1;
    if (setsockopt(cli_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) ==
        -1) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    struct sockaddr_in cli_address = {0};
    cli_address.sin_family = AF_INET;
    cli_address.sin_port = htons(C_PORT);
    cli_address.sin_addr.s_addr = inet_addr(C_IP);
    if (bind(cli_fd, (struct sockaddr *)&cli_address, sizeof(cli_address)) ==
        -1) {
        perror("bind");
        return -1;
    }
    struct sockaddr_in send_address = {0};
    send_address.sin_family = AF_INET;

    char send_buf[1024] = {0};
    int send_res = 0;

    // 链接服务器
    printf("请输入聊天室IP:");
    bzero(send_buf, sizeof(send_buf));
    scanf("%15s", send_buf);
    send_address.sin_addr.s_addr = inet_addr(send_buf);
    while (getchar() != '\n')
        ;
    printf("请输入聊天室端口号:");
    short ports;
    scanf("%4hd", &ports);
    send_address.sin_port = htons(ports);
    while (getchar() != '\n')
        ;
    printf("请输入用户名:");
    bzero(name, sizeof(name));
    scanf("%20s", name);
    while (getchar() != '\n')
        ;
    msg_p messages = getChatMessage("LOGN", "进入聊天室");
    // 绑定完成后 发送登录请求
    send_res = sendto(cli_fd, messages, sizeof(msg), 0,
                      (struct sockaddr *)&send_address, sizeof(send_address));
    if (send_res == -1) {
        perror("sendto");
        return -1;
    }
    printf("成功进入聊天室\n");
    struct pollfd fds[2] = {0};
    fds[0].fd = 0;
    fds[0].events = POLLIN;
    fds[1].fd = cli_fd;
    fds[1].events = POLLIN;

    char wbuf[1024];
    char rbuf[1024];
    while (1) {
        int resp = poll(fds, 2, -1);
        if (resp == -1) {
            perror("poll");
            return -1;
        } else if (resp == 0) {
            printf("timeout\n");
        }

        if (fds[0].revents == POLLIN) {
            bzero(wbuf, sizeof(wbuf));
            fgets(wbuf, sizeof(wbuf), stdin);
            if (strlen(wbuf) > 1) {
                wbuf[strlen(wbuf) - 1] = 0;
            }
            msg_p sendmessages;
            if (strcmp(wbuf, "exit") == 0) {
                sendmessages = getChatMessage("EXIT", "退出聊天室");
            } else {
                sendmessages = getChatMessage("CHAT", wbuf);
            }
            send_res =
                sendto(cli_fd, sendmessages, sizeof(msg), 0,
                       (struct sockaddr *)&send_address, sizeof(send_address));
            if (send_res == -1) {
                perror("sendto");
                return -1;
            }
            if (strcmp(wbuf, "exit") == 0) {
                exit(EXIT_SUCCESS);
            }
        }
        if (fds[1].revents == POLLIN) {
            msg recvmessages = {0};
            struct sockaddr_in rev_address = {0};
            socklen_t rev_len = sizeof(rev_address);

            recvfrom(cli_fd, &recvmessages, sizeof(recvmessages), 0,
                     (struct sockaddr *)&rev_address, &rev_len);

            if (strncmp(recvmessages.type, "LOGN", 4) == 0) {
                // 登陆消息
                if (strncmp(recvmessages.username, name, 4) == 0) {
                    continue;
                }
                printf("*********%s进入聊天室*********\n",
                       recvmessages.username);
            } else if (strncmp(recvmessages.type, "CHAT", 4) == 0) {
                if (strncmp(recvmessages.username, name, 4) == 0) {
                    continue;
                }
                // 普通消息
                printf("%s:%s\n", recvmessages.username, recvmessages.message);
            } else {
                // 某人退出聊天室
                if (strncmp(recvmessages.username, name, 4) == 0) {
                    continue;
                }
                printf("*********%s退出聊天室*********\n",
                       recvmessages.username);
            }
        }
    }

    close(cli_fd);
    return 0;
}
msg_p getChatMessage(char *type, char *message) {
    msg nmsg = {0};
    strcpy(nmsg.type, type);
    strcpy(nmsg.username, name);
    strcpy(nmsg.message, message);
    msg_p nmsgs = &nmsg;
    return nmsgs;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值