首页 > 编程语言 >unix网络编程:解决小型聊天室的用户私发消息问题

unix网络编程:解决小型聊天室的用户私发消息问题

时间:2024-10-25 10:19:48浏览次数:3  
标签:聊天室 sizeof bzero 发消息 unix printf connfd message buff

今天老师布置了一个在线聊天室用户私发消息的问题
思路:在服务端的用户链表中找到要私发的用户名,用其节点里的套接字号发消息,就可以达到私发的效果。

运行效果:
在这里插入图片描述
可以看到,Tom给Bill、Lily群发一个问候消息,Lily私发消息回应Tom。

客户端代码:

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>

#define COMMUNICATION_PORT                55316
#define MSG_S2C_USER_QUEUE_FULL           "The number of users reaches the upper bound"
#define CMD_C2S_QUIT                      "Quit connection"
#define CMD_C2S_OBATIN_USER_LIST          "Obtain the user list from the server"
#define MSG_S2C_SEND_USER_LIST            "The server is sending the user list"
#define MSG_S2C_USER_LIST_HAS_BEEN_SENT   "The user information has been sent"
#define CMD_C2S_SEND_MESSAGE_TO_ALL_USERS "Send a message to all users"
#define MSG_S2C_MESSAGE_TO_ALL_USERS      "The server is sending a message to all users"

// 私发
#define CMD_C2S_SEND_MESSAGE_TO_USER_PRIVATELY "Send a message to a user privately"
#define MSG_S2C_MESSAGE_TO_USER_PRIVATELY      "The server is sending a message to user privately"

//the thread who receives the message sent from the server
static void * messageReceiverThread(void * arg);

int main(int argc, const char ** argv){
    char buff[1024];
    char message[1024];
    char username[10];  // 私发的用户名字
    
    //create the socket
    int connfd = socket(AF_INET, SOCK_STREAM, 0);
    if(connfd == -1){
        printf("1. Create socket failed\n");
        return -1;
    }

    struct sockaddr_in servAddr;
    bzero(&servAddr, sizeof(servAddr));
    servAddr.sin_family      = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr("192.168.83.129");
    servAddr.sin_port        = htons(COMMUNICATION_PORT);

    //connect to the sever
    if (connect(connfd, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1){
        printf("1. Connect failed\n");
        return -1;
    }
    printf("1. Connected to the server!\n");

    bzero(buff, sizeof(buff));
    read(connfd, buff, sizeof(buff));
    if(strcmp(buff, MSG_S2C_USER_QUEUE_FULL) == 0){
        printf("    Message from the server: %s\n", buff);
        return -1;
    }

    //print the welcome message
    printf("    Message from the server: %s\n", buff);

    //send the user name to the server
    char userName[100];
    bzero(userName, sizeof(userName));
    printf("    Input user name: ");
    fgets(userName, 100, stdin);
    userName[strlen(userName) - 1] = '\0';
    bzero(buff, sizeof(buff));
    strcpy(buff, userName);
    write(connfd, buff, strlen(buff));

    //create a thread to receive messages sent from the server
    pthread_t th;
    pthread_create(&th, NULL, messageReceiverThread, (void *)&connfd);

    int quitFlag = 1;
    while(quitFlag){
        
        printf("    Command:\n");
        printf("    1. Obtain the user list.\n");
        printf("    2. Send message to all clients.\n");
        printf("    3. Send message to the client privately.\n");
        printf("    0. Quit.\n");
        printf("    Input Command:\n");
        

        int command;
        scanf("%d", &command);
        getchar();

        switch(command){
            case 0: bzero(buff, sizeof(buff));
                    strcpy(buff, CMD_C2S_QUIT);                   
                    write(connfd, buff, strlen(buff));
                    quitFlag = 0;
                    break;

            case 1: bzero(buff, sizeof(buff));
                    strcpy(buff, CMD_C2S_OBATIN_USER_LIST);
                    write(connfd, buff, strlen(buff));
                    break;

            case 2: bzero(buff, sizeof(buff));
                    strcpy(buff, CMD_C2S_SEND_MESSAGE_TO_ALL_USERS);
                    write(connfd, buff, strlen(buff));

                    printf("    Message: ");
                    bzero(message, sizeof(message));
                    fgets(message, 1024, stdin);
                    message[strlen(message) - 1] = '\0';
                    bzero(buff, sizeof(buff));
                    strcpy(buff, message);
                    write(connfd, buff, strlen(buff));
                    break;
			
			case 3:bzero(buff, sizeof(buff));
                    strcpy(buff, CMD_C2S_SEND_MESSAGE_TO_USER_PRIVATELY);
                    write(connfd, buff, strlen(buff));
					
					printf("    Priavte Username: ");
                    bzero(username, sizeof(username));
                    fgets(username, 10, stdin);
                    username[strlen(username) - 1] = '\0';
                    bzero(buff, sizeof(buff));
                    strcpy(buff, username);
                    write(connfd, buff, strlen(buff));					
					
                    printf("    Message: ");
                    bzero(message, sizeof(message));
                    fgets(message, 1024, stdin);
                    message[strlen(message) - 1] = '\0';
                    bzero(buff, sizeof(buff));
                    strcpy(buff, message);
                    write(connfd, buff, strlen(buff));
                    break;
								
            default:
                    printf("    Unknown command!\n");

        }
    }

    close(connfd);
    printf("2. Sokcet is closed\n");
    return 0;
}

static void * messageReceiverThread(void * arg){
    int connfd = * (int *)arg;
    char buff[1024];

    while(1){
        //receive message from the server
        bzero(buff, sizeof(buff));
        read(connfd, buff, sizeof(buff));

        
        //the server is sending the user list
        if(strcmp(buff, MSG_S2C_SEND_USER_LIST) == 0){
            bzero(buff, sizeof(buff));
            read(connfd, buff, sizeof(buff));
            while(strcmp(buff, MSG_S2C_USER_LIST_HAS_BEEN_SENT) != 0){ 
                printf("    Message from the server: %s\n", buff);       
                bzero(buff, sizeof(buff));
                read(connfd, buff, sizeof(buff));     
            } 
        }

        //the server is sending a message to all users
        if(strcmp(buff, MSG_S2C_MESSAGE_TO_ALL_USERS) == 0){
            bzero(buff, sizeof(buff));
            read(connfd, buff, sizeof(buff));
            printf("    %s\n", buff);
        }
        
        //the server is sending a message to user privately
        if(strcmp(buff, MSG_S2C_MESSAGE_TO_USER_PRIVATELY) == 0){
            bzero(buff, sizeof(buff));
            read(connfd, buff, sizeof(buff));
            printf("    %s\n", buff);
        }        
    }


    return NULL;
}

服务端代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>

#define COMMUNICATION_PORT                55316
#define MAX_CLIENTS                       3
#define MSG_S2C_USER_QUEUE_FULL           "The number of users reaches the upper bound"
#define MSG_S2C_WELCOME_MESSAGE           "Welcome connect to the server"
#define CMD_C2S_QUIT                      "Quit connection"
#define CMD_C2S_OBATIN_USER_LIST          "Obtain the user list from the server"
#define MSG_S2C_SEND_USER_LIST            "The server is sending the user list"
#define MSG_S2C_USER_LIST_HAS_BEEN_SENT   "The user information has been sent"
#define CMD_C2S_SEND_MESSAGE_TO_ALL_USERS "Send a message to all users"
#define MSG_S2C_MESSAGE_TO_ALL_USERS      "The server is sending a message to all users"

// 私发
#define CMD_C2S_SEND_MESSAGE_TO_USER_PRIVATELY "Send a message to a user privately"
#define MSG_S2C_MESSAGE_TO_USER_PRIVATELY      "The server is sending a message to user privately"

//struct of user node
struct userNode{
    int             userID;
    char            userName[100];
    int             connfd;
    struct userNode * next;
};

//global variables
struct userNode * userList;
int userCount, historicalConnections;

//the child threads call this function
static void * childThread(void * arg);

int main(int argc, const char ** argv){
    struct sockaddr_in clientAddr;
    socklen_t len;
    char buff[1024];

    //initialize the golbal variables
    userList              = (struct userNode *)malloc(sizeof(struct userNode));
    userList->next        = NULL;
    userCount             = 0;
    historicalConnections = 0;

    //create the socket
    int socketServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(socketServer == -1){
        printf("1. Create socket failed.\n");
        return -1;
    }
    printf("1. The socket is created.\n");

    //bind the socket
    struct sockaddr_in servAddr;
    bzero(&servAddr, sizeof(servAddr));
    servAddr.sin_family      = AF_INET;
    servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servAddr.sin_port        = htons(COMMUNICATION_PORT);
    if(bind(socketServer, (struct sockaddr *)&servAddr, sizeof(servAddr)) == -1){
        printf("2. Bind failed.");
        return -1;    
    }
    printf("2. The address is bound.\n");

    //convert the state into listen state
    if(listen(socketServer, 5) == -1){
        printf("3. Listen failed.\n");
        return -1;
    }
    printf("3. Listen state.\n");

    printf("4. Waiting for connection.\n");

    while(1){
        //wait for connection
        int connfd = accept(socketServer, (struct sockaddr *)(&clientAddr), &len);
        if(connfd == -1){
            printf("4. Accept failed\n");
            return -1;
        }

        printf("    A new client is connecting to the server.\n");
        
        if(userCount < MAX_CLIENTS){
            //create the child thread
            pthread_t th;
            pthread_create(&th, NULL, childThread, (void *) &connfd);
        }

        //the number of clients reaches the upper bound
        else{
            printf("    The number of clients reaches the upper bound, connection is forbidden.\n");
            bzero(buff, sizeof(buff));
            strcpy(buff, MSG_S2C_USER_QUEUE_FULL);
            write(connfd, buff, strlen(buff));
        }        
    }
    
    free(userList);
    close(socketServer);
    return 0;
}

static void * childThread(void * arg){
    int connfd = * (int *)arg;
    char buff[1024];

    //send the welcome message
    bzero(buff, sizeof(buff));
    strcpy(buff, MSG_S2C_WELCOME_MESSAGE);
    write(connfd, buff, strlen(buff));

    //create a user node to store the information
    struct userNode * cn = (struct userNode *)malloc(sizeof(struct userNode));

    //insert the user node to the end of the user list
    struct userNode * p = userList;
    while(p->next != NULL)
        p = p->next;
    p->next = cn;
        
    //obtain the user name and initialize the user node
    cn->connfd = connfd;
    cn->userID = historicalConnections++;
    cn->next   = NULL;

    bzero(buff, sizeof(buff));
    read(connfd, buff, sizeof(buff));
    strcpy(cn->userName, buff);
    printf("    New client: connfd(%d), userID(%d), userName(%s), TID(%ld)\n", 
        cn->connfd, cn->userID, cn->userName, pthread_self());
    userCount++;

    int quitFlag = 1;
    while(quitFlag){
        //obtain the command from the client
        bzero(buff, sizeof(buff));
        read(connfd, buff, sizeof(buff));

        //user quits the connection
        if(strcmp(buff, CMD_C2S_QUIT) == 0){
            p = userList;
            while(p->next != cn)
                p = p->next;
            p->next = cn->next;

            userCount--;
            
            quitFlag = 0;

            printf("    Client: connfd(%d), userID(%d), userName(%s) quits the connection, clientCount(%d).\n",
                cn->connfd, cn->userID, cn->userName, userCount);
        }

        //user wants to obtain the user list
        if(strcmp(buff, CMD_C2S_OBATIN_USER_LIST) == 0){
            printf("    message from the client(%d): %s\n", connfd, buff);
            //tell the client that the server is about to send the user information
            bzero(buff, sizeof(buff));
            strcpy(buff, MSG_S2C_SEND_USER_LIST);
            write(connfd, buff, strlen(buff));
            sleep(0.1);

            //fetch the user information
            p = userList->next;
            int clientIdx = 1;
            while(p != NULL){
                //send the information of all clients
                bzero(buff, sizeof(buff));
                sprintf(buff, "%d. userID: %d userName: %s", clientIdx++, p->userID, p->userName);
                printf("    Message to the client(%d): %s\n", connfd, buff);
                write(connfd, buff, sizeof(buff));
                sleep(0.1);
                p = p->next;
            }

            //tell the client that the user information have been sent
            bzero(buff, sizeof(buff));
            strcpy(buff, MSG_S2C_USER_LIST_HAS_BEEN_SENT);
            write(connfd, buff, strlen(buff));
        }

        //user wants to send a message to all users
        if(strcmp(buff, CMD_C2S_SEND_MESSAGE_TO_ALL_USERS) == 0){
            printf("    message from the client(%d): %s\n", connfd, buff);

            //receive the message
            bzero(buff, sizeof(buff));
            read(connfd, buff, sizeof(buff));

            char message[2048];
            bzero(message, sizeof(message));
            sprintf(message, "Message from %s to all users: %s", cn->userName, buff);

            //send message to all users
            p = userList->next;
            while(p != NULL){
                if(p->connfd != connfd){
                    bzero(buff, sizeof(buff));
                    strcpy(buff, MSG_S2C_MESSAGE_TO_ALL_USERS);
                    write(p->connfd, buff, strlen(buff));
                    sleep(0.1);
					
                    write(p->connfd, message, strlen(message));
                    printf("    Send message from %s to %s\n", cn->userName, p->userName);
                    sleep(0.1);
                }
                p = p->next;
            }
        }
        
        //user wants to send a message to user privately
        if(strcmp(buff, CMD_C2S_SEND_MESSAGE_TO_USER_PRIVATELY) == 0){
            printf("    message from the client(%d): %s\n", connfd, buff);
			
			//receive the username
            bzero(buff, sizeof(buff));
            read(connfd, buff, sizeof(buff));
 
            char username[10];
            bzero(username, sizeof(username));
			strcpy(username, buff);	
					
            //receive the message
            bzero(buff, sizeof(buff));
            read(connfd, buff, sizeof(buff));

            char message[2048];
            bzero(message, sizeof(message));
            sprintf(message, "Message from %s to %s privately: %s", cn->userName, username, buff); // 把消息写入到 message 句柄中,待发送
			
            //send message to the user privately
            p = userList->next;
            while(p != NULL){
                if(strcmp(p->userName, username) == 0){     // 寻找指定的私发用户
                    bzero(buff, sizeof(buff));
                    strcpy(buff, MSG_S2C_MESSAGE_TO_USER_PRIVATELY);
                    write(p->connfd, buff, strlen(buff));
                    sleep(0.1);

                    write(p->connfd, message, strlen(message));
                    printf("    Send message from %s to %s privately\n", cn->userName, p->userName);
                    sleep(0.1);
                    break;
                }
                p = p->next;
            }
        }
    }

    close(connfd);
    free(cn);
    return NULL;
}

标签:聊天室,sizeof,bzero,发消息,unix,printf,connfd,message,buff
From: https://blog.csdn.net/m0_74054477/article/details/143219138

相关文章

  • 极速、便捷!一个接入 AI 的匿名在线即时聊天室!
    大家好,我是Java陈序员。之前给大家推荐过一款基于livekit和Next.js的匿名聊天室。今天,再给大家介绍一个便捷开源的匿名在线聊天室,支持AI功能!关注微信公众号:【Java陈序员】,获取开源项目分享、AI副业分享、超200本经典计算机电子书籍等。项目介绍AQChat——一个已接......
  • 使用application模拟聊天室
    <%@pagelanguage="java"contentType="text/html;charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPEhtml><html><head><metacharset="UTF-8"><title>Session测试</title......
  • 【Docker】Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is
    问题描述CannotconnecttotheDockerdaemonatunix:///var/run/docker.sock.Isthedockerdaemonrunning?原因分析尝试运行Docker命令时,系统无法与Docker守护程序(daemon)通信。Docker服务未运行。解决方案确保Docker服务已经启动。通过在终端中运行s......
  • Chromium 中HTML5 WebSocket收发消息分析c++(一)
    一、WebSocket前端接口定义:WebSocket 对象提供了用于创建和管理 WebSocket 连接,以及可以通过该连接发送和接收数据的API。使用 WebSocket() 构造函数来构造一个 WebSocket。构造函数WebSocket(url[,protocols])返回一个 WebSocket 对象。常量ConstantValueWeb......
  • Chromium 中HTML5 WebSocket收发消息分析c++(二)
    看下websocket调用过程:基本定义参考上一篇:Chromium中HTML5WebSocket收发消息分析c++(一)-CSDN博客一、前端测试用例 参考:HTML5WebSocket|菜鸟教程(runoob.com) websocket.html文件如下:<!DOCTYPEHTML><html><head><metacharset="utf-8"><title>Web......
  • Veritas NetBackup 10.5 (Unix, Linux, Windows) - 领先的企业备份解决方案
    VeritasNetBackup10.5(Unix,Linux,Windows)-领先的企业备份解决方案The#1enterprisebackupandrecoverysolution.请访问原文链接:https://sysin.org/blog/veritas-netbackup-10/查看最新版。原创作品,转载请保留出处。作者主页:sysin.org备份和恢复软件解决方案领......
  • 利用线程池和网络动态库实现多人聊天室
    利用线程池和网络动态库实现多人聊天室概述本项目实现一个简单的多人聊天室,采用C语言编写,利用线程池和网络动态库,实现服务端消息转发和客户端消息接收。服务端服务端主要负责管理客户端连接,接收并转发消息。代码实现#include<stdio.h>#include<stdlib.h>#include......
  • 聊天室(Websocket+Node)
    文章目录目录文章目录前言二、使用步骤1.服务端代码 2.客户端代码3.成果展示总结前言使用Websocket+Node实现一个简单的聊天室的功能,以及包含保持websocket长时间连接永不断开的两种方法一、Websocket是什么?WebSocket是一种网络通信协议,是 HTML5 开始提供......
  • C语言 实现 unix时间戳转换到自定义 tm结构体
    之前使用ESP32写了一个闹钟,免得我老是把手机闹钟给滑了就不知该起床了原本想用标准库解决的,但是这个时间一直不准,逼得用SNTP获取了步进单位为(second)的时间戳,然后使用GPtimer来维持时间戳才算是把精准计时给解决了废话不多说,直接上代码typedefstruct{intyear;......
  • NIO实现聊天室之:一切都要从网络编程的基础开始聊起!
    一、写在开头大家好,Build哥回来啦!停更了大概2个月之久,之前有段时间去写小说去了,后来又因为公司活太多,牛马干的太投入,就拉下了博客的更新,国庆节期间,难得的闲下来,准备回归老本行啦。大致的翻看了一下之前更新的内容,已经写到了Java的IO部分,作为网络传输的一大重点知识,IO至关重要,而......