C语言 小代码 TCP转发信息,实现各个客户端之间相互通信

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef struct msg_t
{
    char fb[5];
    char msg[1024];
} msg_t;

typedef struct list
{
    struct sockaddr_in addr;
    struct list *next;
    int fb;
} Node;
static int num;
static Node *list;

// 初始化好友列表
void init_list();
void init_list()
{
    list = malloc(sizeof(Node));
    memset(&list->addr, 0, sizeof(list->addr));
    list->next = NULL;
    list->fb = 0;
    num = 0;
}

// 创建新节点
Node *create_Node();
Node *create_Node()
{
    Node *New_Node = malloc(sizeof(Node));
    memset(New_Node, 0, sizeof(Node));
    New_Node->next = NULL;
    return New_Node;
}

// 插入节点链表
Node *insert_list(Node *add_Node);
Node *insert_list(Node *add_Node)
{
    add_Node->next = list->next;
    list->next = add_Node;
}

// 删除节点
int rm_Node(Node *rm_Node);
int rm_Node(Node *rm_Node)
{
    Node *temp = list;
    while (1)
    {
        if (temp == NULL && temp != list)
        {
            return -1;
        }
        if (temp->next == rm_Node)
        {
            temp->next = rm_Node->next;
            free(rm_Node);
            return 0;
        }
        temp = temp->next;
    }
    return 0;
}

// 向所有客户机发送共同信息
void sendallfb(char *info);
void sendallfb(char *info)
{
    Node *temp = list->next;
    while (1)
    {
        if (temp == NULL)
        {
            break;
        }
        write(temp->fb, info, strlen(info));
        temp = temp->next;
    }
}

// 遍历好友列表
void print_list();
void print_list()
{
    char info[521 * 10];
    memset(info, 0, sizeof(memset));
    char Tips[100] = {"---------------------好友列表-------------------\n"};
    strcat(info, Tips);
    if (list == NULL)
    {
        return;
    }
    if (list->next == NULL)
    {
        char no_num[50] = {"没有人上线\n"};
        strcat(info, no_num);
    }
    char num_tips[100];
    sprintf(num_tips, "有%d个好友在线\n", num);
    strcat(info, num_tips);
    char ip_fb[1000];
    memset(ip_fb, 0, sizeof(ip_fb));
    char temp_ip_fb[100];
    Node *temp = list->next;
    int onlinfb;

    while (1)
    {
        if (temp == NULL)
        {
            break;
        }
        memset(temp_ip_fb, 0, sizeof(temp_ip_fb));
        printf("IP:%s fb=%d(在线)\n", inet_ntoa(temp->addr.sin_addr), temp->fb);
        sprintf(temp_ip_fb, "IP:%s fb=%d(在线)\n", inet_ntoa(temp->addr.sin_addr), temp->fb);
        strcat(ip_fb, temp_ip_fb);
        onlinfb = temp->fb;
        temp = temp->next;
    }
    // sprintf(info, "%s%s%s", Tips, num_tips, ip_fb);
    strcat(info, ip_fb);
    printf("\n");
    printf("info=%s\n", info);
    sendallfb(info);
    printf("\n");
}

int main(int argc, char const *argv[])
{
    // 初始化好友列表
    init_list();

    // 创建socket
    int fb = socket(AF_INET, SOCK_STREAM, 0);
    if (fb < 0)
    {
        perror("socket");
        return 0;
    }
    // 绑定主机信息
    struct sockaddr_in addr;     // 定义结构体
    addr.sin_family = AF_INET;   // 设置为IPV4
    addr.sin_port = htons(8969); // 设置端口号为8080
    addr.sin_addr.s_addr = INADDR_ANY;

    int on = 1;
    setsockopt(fb, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));//端口复用
    // 绑定socket
    if (bind(fb, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind fail");
    }

    // 设置监听,,模式
    if (listen(fb, 100))
    {
        perror("listen");
    }
    int maxfb = fb;
    while (1)
    {
        Node *temp = list->next;
        // 多路复用
        fd_set rfbs;
        // 清空集合
        FD_ZERO(&rfbs);
        // 添加服务器描述符
        FD_SET(fb, &rfbs);
        // 添加标志输入描述符
        FD_SET(0, &rfbs);

        msg_t msg;
        char op_tip[200];
        memset(op_tip, 0, sizeof(op_tip));
        strcat(op_tip, "--------------------操作提示--------------------\n");
        while (1)
        {
            if (temp == NULL)
            {
                break;
            }
            FD_SET(temp->fb, &rfbs);
            temp = temp->next;
        }

        if (num != 0)
        {
            strcat(op_tip, "发送信息格式:xxxx msg\n\n");
            strcat(op_tip, "xxxx为对方fb,msg为短信内容\n\n");
        }
        sendallfb(op_tip);
        int ret = select(maxfb + 1, &rfbs, NULL, NULL, NULL);
        if (ret > 0)
        {

            temp = list->next;
            while (1)
            {
                if (temp == NULL)
                {
                    break;
                }

                if (FD_ISSET(temp->fb, &rfbs))
                {
                    memset(&msg, 0, sizeof(msg));
                    if (read(temp->fb, &msg, sizeof(msg)) <= 0)
                    {
                        char down_line[200];
                        memset(down_line, 0, sizeof(down_line));

                        strcat(down_line, "--------------------下线通知--------------------\n");

                        char down_line_info[100];
                        sprintf(down_line_info, "您的好友IP=%s fb=%d下线\n", inet_ntoa(temp->addr.sin_addr), temp->fb);
                        strcat(down_line, down_line_info);
                        if (rm_Node(temp) == -1)
                        {
                            printf("删除节点失败\n");
                        }
                        sendallfb(down_line);
                        num--;
                        print_list();
                        break;
                    }
                    char msg_info[1000];
                    memset(msg_info, 0, sizeof(msg_info));
                    strcat(msg_info, "---------------------信息通知-------------------\n");

                    char rcv_info[100];
                    sprintf(rcv_info, "IP:%s fb=%d(在线)发来消息:\n", inet_ntoa(temp->addr.sin_addr), temp->fb);
                    strcat(msg_info, rcv_info);
                    msg.msg[strlen(msg.msg)] = '\n';
                    strcat(msg_info, msg.msg);
                    msg.fb[4] = '\0';
                    if (write(atoi(msg.fb), msg_info, strlen(msg_info)) < 0)
                    {
                        char error_info[70] = {"发送失败,短息格式有问题,或者对方不在线\n"};
                        write(temp->fb, error_info, strlen(error_info));
                    }
                    break;
                }
                temp = temp->next;
            }

            // 退出机制
            if (msg.msg[0] == '1')
            {
                break;
            }

            // 监听键盘输入
            if (FD_ISSET(0, &rfbs))
            {
                int op;
                scanf("%d", &op);
                if (op == 1)
                {
                    break;
                }
            }

            // 监听是否有人上线
            if (FD_ISSET(fb, &rfbs))
            {
                char on_line_info[200];
                memset(on_line_info, 0, sizeof(on_line_info));
                socklen_t len = sizeof(list->addr);
                Node *New_node = create_Node();
                New_node->fb = accept(fb, (struct sockaddr *)&New_node->addr, &len);
                if (New_node->fb > 0)
                {

                    strcat(on_line_info, "---------------------上线通知-------------------\n");
                    char up_line[100];
                    memset(up_line, 0, sizeof(up_line));
                    sprintf(up_line, "您的好友IP=%s fb=%d已上线\n", inet_ntoa(New_node->addr.sin_addr), New_node->fb);
                    char myinfo[150];
                    sprintf(myinfo, "本机信息:IP=%s fb=%d\n", inet_ntoa(New_node->addr.sin_addr), New_node->fb);
                    write(New_node->fb, myinfo, strlen(myinfo));
                    strcat(on_line_info, up_line);
                    insert_list(New_node);
                    maxfb = New_node->fb;
                    num++;
                    sendallfb(on_line_info);
                    print_list();
                }
            }
        }
    }

    // 退出关闭
    Node *tempe = list->next;
    close(fb);
    while (1)
    {
        if (tempe == NULL)
        {
            break;
        }
        close(tempe->fb);
        tempe = tempe->next;
    }

    return 0;
}

                不懂可自行网主页寻找相应API解读,或私信(但不一定回)

你可能感兴趣的:(小代码,c语言,tcp/ip,windows)