【聊天程序】

1.服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <poll.h>

#define IP "192.168.122.156"
#define PORT 8888
#define BCPORT 8889

typedef struct Node {
    char ip[128];
    int port;
    struct Node* next;
} * Linklist;


Linklist createNode() {
    Linklist s = (Linklist)malloc(sizeof(struct Node));
    if (NULL == s) {
        return NULL;
    }
    memset(s->ip, 0, sizeof(s->ip));
    s->port = 0;
    s->next = NULL;
    return s;
}

int isElementInList(char* ip,int port, Linklist head) {
    Linklist current = head;
    while (current != NULL) {
        if (strcmp(current->ip,ip)==0 && current->port==port) {
            return 1;  // 元素存在于链表中
        }
        current = current->next;
    }
    return 0;  // 元素不存在于链表中
}

Linklist insertHead(char* ip, int port, Linklist head) {
    Linklist s = createNode();
    if (NULL == s) {
        return head;
    }
    if (isElementInList(ip,port,head)==1)
    {
        return head;
    }
            
    strncpy(s->ip, ip, sizeof(s->ip) - 1);
    s->port = port;
    if (head == NULL) {
        head = s;
    } else {
        s->next = head;
        head = s;
    }
    return head;
}

struct userinfo {
    char name[128];
    char text[128];
    int mode;
};

int broadcast(struct userinfo user) {
    int sfd = -1;
    if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket error");
        return -1;
    }

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(BCPORT);
    sin.sin_addr.s_addr = inet_addr(IP);

    int broadcast = 1;
    if (setsockopt(sfd, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)) == -1) {
        perror("setsockopt error");
        return -1;
    }
    sendto(sfd, &user, sizeof(user), 0, (struct sockaddr*)&sin, sizeof(sin));
    close(sfd);
    return 0;
}
int sendAllMessage(struct userinfo user, Linklist head) {
    int cfd = -1;
    if ((cfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        return -1;
    }

    struct sockaddr_in sin;
    if (head == NULL) {
        close(cfd);
        return -1;
    }

    Linklist p = head;
    while (p != NULL) {
        sin.sin_family = AF_INET;
        sin.sin_port = htons(p->port);
        sin.sin_addr.s_addr = inet_addr(p->ip);
        sendto(cfd, &user, sizeof(user), 0, (struct sockaddr*)&sin, sizeof(sin));
        p = p->next;
    }

    close(cfd);
    return 0;
}

int main(int argc, char const* argv[]) {
    
    int sfd = -1;
    if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket error");
        return -1;
    }

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    sin.sin_addr.s_addr = inet_addr(IP);

    if (bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
        perror("bind error");
        return -1;
    }

    struct sockaddr_in cin;
    socklen_t socklen = sizeof(cin);

    printf("[%s:%d]:服务器端已启动\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port));
    struct userinfo user;
    struct userinfo admin;

    struct pollfd fds[2];
    fds[0].fd = 0;
    fds[0].events = POLLIN;

    fds[1].fd = sfd;
    fds[1].events = POLLIN;

    Linklist head = NULL;
    while (1) {
        int res = poll(fds, 2, -1);
        if (res == -1) {
            perror("poll error");
            return -1;
        } else if (res == 0) {
            printf("timeout\n");
            return -1;
        }

        char client_ip[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &cin.sin_addr, client_ip, sizeof(client_ip));
        
        head = insertHead(client_ip, ntohs(cin.sin_port), head);


        if (fds[0].revents == POLLIN) {
            bzero(&admin,sizeof(admin));
            admin.mode=1;
            sprintf(admin.name,"系统");
            fgets(admin.text,sizeof(admin.text),stdin);
            admin.text[strlen(admin.text) - 1] = 0;
            sendAllMessage(admin, head);
        }

        if (fds[1].revents == POLLIN) {
            recvfrom(sfd, &user, sizeof(user), 0, (struct sockaddr*)&cin, &socklen);
            if (user.mode == 2) {
                printf("%s:连接成功\n", user.name);
                strncpy(user.text, "连接成功", sizeof(user.text) - 1);
                sendAllMessage(user, head);
            } else if (user.mode == 1) {
                printf("%s:%s\n", user.name, user.text);
            }

            if (strcmp(user.text, "连接成功") != 0) {
                sendAllMessage(user, head);
            }

            memset(&user, 0, sizeof(user));
        }
        
    }

    close(sfd);
    return 0;
}

2.客户端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <poll.h>

#define IP "192.168.122.156"
#define PORT 8888
#define BCPORT 8889

struct userinfo {
    char name[128];
    char text[128];
    int mode;
};

int main() {
    int cfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (cfd == -1) {
        perror("socket error");
        return -1;
    }

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_port = htons(PORT);
    sin.sin_addr.s_addr = inet_addr(IP);

    struct sockaddr_in cin;
    socklen_t socklen = sizeof(cin);

    struct userinfo user;
    user.mode = 2;  // 客户端标识为2

    printf("请输入您的用户名:");
    fgets(user.name, sizeof(user.name), stdin);
    user.name[strcspn(user.name, "\n")] = '\0';  // 去掉换行符

    sendto(cfd, &user, sizeof(user), 0, (struct sockaddr*)&sin, sizeof(sin));

    printf("连接成功,您可以开始聊天了。\n");

    struct pollfd fds[2];
    fds[0].fd = 0;
    fds[0].events = POLLIN;

    fds[1].fd = cfd;
    fds[1].events = POLLIN;

    while (1) {
        int res = poll(fds, 2, -1);
        if (res == -1) {
            perror("poll error");
            return -1;
        } else if (res == 0) {
            printf("timeout\n");
            return -1;
        }

        if (fds[0].revents == POLLIN) {
            user.mode = 1;
            fgets(user.text, sizeof(user.text), stdin);
            user.text[strcspn(user.text, "\n")] = '\0';  // 去掉换行符

            sendto(cfd, &user, sizeof(user), 0, (struct sockaddr*)&sin, sizeof(sin));
        }

        if (fds[1].revents == POLLIN) {
            recvfrom(cfd, &user, sizeof(user), 0, (struct sockaddr*)&cin, &socklen);
            printf("%s:%s\n",user.name, user.text);
        }
    }

    close(cfd);
    return 0;
}

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值