day6_网络编程

网络聊天室

客户端

main.c

#include "include/errorAndHead.h"

void hander(int sig)
{
    while (waitpid(-1, NULL, WNOHANG) > 0)
        ;
}

int main(int argc, const char *argv[])
{
    /* 捕获 SIGCHLD 信号 hander 处理*/
    if (signal(SIGCHLD, hander) == SIG_ERR)
    {
        ERR_MSG("socket");
        return -1;
    }

    msg Msg = {};
    Msg.type = 'L';
    strcpy(Msg.name, loginUI(Msg.name));

    // 创建客户端socket
    int cli_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (cli_fd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);          // 主机字节序转网络字节序
    sin.sin_addr.s_addr = inet_addr(SER_IP); // 点分十进制转网络字节序
    socklen_t sin_len = sizeof(sin);
    /* 该进程只服务的用户名 */
    /*  char name[20] = "";
     strcpy(name, Msg.name); */
    // 将聊天用户的基本信息发送给服务器
    if (sendto(cli_fd, &Msg, sizeof(Msg), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("sendto");
        return -1;
    }
    // 创建子进程
    pid_t pid = fork();
    if (pid == 0)
    {
        char name[20] = "";
        strcpy(name, Msg.name);
        // 子进程
        while (1)
        {
            memset(&Msg, 0, sizeof(Msg));
            fgets(Msg.text, sizeof(Msg.text), stdin);
            Msg.text[strlen(Msg.text) - 1] = 0;
            if (strcmp(Msg.text, "quit") == 0)
            {
                /* 如果输入的是quit那么 通知下线 并且退出进程,并通知父进程死亡 */
                exit_chat(cli_fd, Msg, name, sin);
                kill(getppid(), SIGKILL);
                break;
            }
            msg_chat(cli_fd, Msg, name, sin);
        }

        exit(EXIT_SUCCESS);
    }
    else if (pid > 0)
    {
        // 父进程用来接收数据
        while (1)
        {
            memset(&Msg, 0, sizeof(Msg));
            if (recvfrom(cli_fd, &Msg, sizeof(Msg), 0, NULL, NULL) < 0)
            {
                ERR_MSG("recvfrom");
                return -1;
            }
            switch (Msg.type)
            {
            case 'L':
                // printf("system msg : %s\n", Msg.text);
                rec_login(Msg);
                break;
            case 'Q':
                // printf("system msg : %s\n", Msg.text);
                quitc_login(Msg);
                break;
            case 'C':
                rec_chat(Msg);
                break;
            default:
                break;
            }
        }
        exit(EXIT_SUCCESS);
    }

    close(cli_fd);

    return 0;
}

函数库

#include "include/errorAndHead.h"

char *loginUI(char *username)
{
    memset(username, 0, sizeof(username));
    char e;
    printf("————————欢迎来到多人聊天室————————\n");
    printf("键入ENTRE继续...\n");
    scanf("%c", &e);
    if (e != '\n')
    {
        exit(EXIT_SUCCESS);
    }
    printf("请输入姓名->>>");
    scanf("%s", username);
    return username;
}

int rec_login(msg Msg)
{
    if (Msg.type == 'L')
    {
        printf("system msg : %s\n", Msg.text);
    }

    return 0;
}

int exit_chat(int cli_fd, msg Msg, char *name, struct sockaddr_in sin)
{
    strcpy(Msg.name, name);
    Msg.type = 'Q';
    if (sendto(cli_fd, &Msg, sizeof(Msg), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("sendto");
        return -1;
    }

    return 0;
}

int quitc_login(msg Msg)
{
    if (Msg.type == 'Q')
    {
        printf("system msg : %s\n", Msg.text);
    }
    return 0;
}

int msg_chat(int cli_fd, msg Msg, char *name, struct sockaddr_in sin)
{
    strcpy(Msg.name, name);
    Msg.type = 'C';
    if (sendto(cli_fd, &Msg, sizeof(Msg), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
        ERR_MSG("sendto");
        return -1;
    }
    return 0;
}

int rec_chat(msg Msg)
{
    if (Msg.type == 'C')
    {
        printf("%s\n",Msg.text);
    }
    return 0;
}

服务器

main.c

#include "include/errorAndHead.h"

void hander(int sig)
{
    while (waitpid(-1, NULL, WNOHANG) > 0)
        ;
}

int main(int argc, const char *argv[])
{
    /* 捕获 SIGCHLD 信号 hander 处理*/
    if (signal(SIGCHLD, hander) == SIG_ERR)
    {
        ERR_MSG("socket");
        return -1;
    }

    // 创建服务器socket
    int ser_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (ser_fd < 0)
    {
        ERR_MSG("socket");
        return -1;
    }

    // 绑定IP和port
    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(SER_PORT);
    sin.sin_addr.s_addr = inet_addr(SER_IP);
    if (bind(ser_fd, (struct sockaddr *)&sin, sizeof(sin)) != 0)
    {
        ERR_MSG("bind");
        return -1;
    }

    // 创建进程
    int pid = fork();
    if (pid > 0)
    {
        // 父进程, 接收消息
        user_linklist *head = (user_linklist *)malloc(sizeof(user_linklist));
        head->len = 0;
        head->next = NULL;
        // 发送方接收容器
        struct sockaddr_in rec_cin;
        socklen_t rec_cin_len = sizeof(rec_cin);
        msg Msg;

        while (1)
        {
            memset(&Msg, 0, sizeof(Msg));
            if (recvfrom(ser_fd, &Msg, sizeof(Msg), 0, NULL,NULL) < 0)
            {
                ERR_MSG("recvfrom");
                return -1;
            }
            switch (Msg.type)
            {
            case 'L':
                rec_login(ser_fd, rec_cin, Msg, head);
                break;
            case 'Q':
                quit_login(ser_fd, rec_cin, Msg, head);
                break;
            case 'C':
                msg_chat(ser_fd, rec_cin, Msg, head);
                break;
            default:
                break;
            }
        }

        free(head);
        head = NULL;
        exit(EXIT_SUCCESS);
    }
    else if (pid == 0)
    {
        // 终端获取文本
        exit(EXIT_SUCCESS);
    }

    close(ser_fd);
    return 0;
}

函数库

#include "include/recive.h"

int rec_login(int ser_fd, struct sockaddr_in rec_cin, msg Msg, user_linklistPtr head)
{
    /* 自己的终端打印成功登录 */
    printf("成功登录---IP:%s PORT:%d 用户名:%s\n", inet_ntoa(rec_cin.sin_addr), ntohs(rec_cin.sin_port), Msg.name);
    Msg.type = 'L';
    strcpy(Msg.text, "");
    sprintf(Msg.text, "——————%s 成功上线——————\n", Msg.name);
    /* 成功登录后,向所有人发送某人成功 上线 */
    user_linklistPtr ptr = head;
    while (ptr->next != NULL)
    {
        ptr = ptr->next;
        if (sendto(ser_fd, &Msg, sizeof(Msg), 0, (struct sockaddr *)&(ptr->data), sizeof(ptr->data)) < 0)
        {
            ERR_MSG("sendto");
            return -1;
        }
    }

    // 将登录的用户放入内存
    user_linklist *node = (user_linklist *)malloc(sizeof(user_linklist));
    node->next = NULL;
    node->data = rec_cin;
    head->next = node;
    head->len++;

    return 0;
}

int quit_login(int ser_fd, struct sockaddr_in rec_cin, msg Msg, user_linklistPtr head)
{
    printf("退出成功---IP:%s PORT:%d 用户名:%s\n", inet_ntoa(rec_cin.sin_addr), ntohs(rec_cin.sin_port), Msg.name);
    strcpy(Msg.text, "");
    sprintf(Msg.text, "——————%s 下线了——————\n", Msg.name);
    user_linklistPtr ptr = head;
    while (ptr->next != NULL)
    {
        ptr = ptr->next;
        if (sendto(ser_fd, &Msg, sizeof(Msg), 0, (struct sockaddr *)&(ptr->data), sizeof(ptr->data)) < 0)
        {
            ERR_MSG("sendto");
            return -1;
        }
    }

    /* 在链表中删除下线的用户 */
    // 后续优化不影响程序运行
}

int msg_chat(int ser_fd, struct sockaddr_in rec_cin, msg Msg, user_linklistPtr head)
{
    if (Msg.type != 'C')
    {
        return 0;
    }

    user_linklistPtr ptr = head;
    while (ptr->next != NULL)
    {
        ptr = ptr->next;
        if (sendto(ser_fd, &Msg, sizeof(Msg), 0, (struct sockaddr *)&(ptr->data), sizeof(ptr->data)) < 0)
        {
            ERR_MSG("sendto");
            return -1;
        }
    }
}

你可能感兴趣的:(作业,网络)