网络编程项目(聊天室项目)

一、实现目标

一个在Linux下可以使用的聊天软件,要求至少实现如下功能:
1. 采用Client/Server架构
2. Client A 登陆聊天服务器前,需要注册自己的ID和密码
3. 注册成功后,Client A 就可以通过自己的ID和密码登陆聊天服务器
4. 多个Client X 可以同时登陆聊天服务器之后,与其他用户进行通讯聊天
5. Client A 成功登陆后可以查看当前聊天室内其他子啊先用户Client x
6. Client A 可以选择发消息给某个特定的 Client x,即“悄悄话”功能
7. Client A 可以选择发消息给全部的在线用户,即“群发消息”功能
8. Client A 在退出时需要保存聊天记录
9. Server 端维护一个所有登陆用户的聊天会的记录文件,以便查看

可以选择实现的附加功能:
1. Server 可以内建一个特殊权限的账号admin,用于管理聊天室
2. Admin 可以将某个Client X“踢出聊天室”
3. Admin 可以将某个Client X“设为只能旁听,不能发言”
4. Client 端发言增加表情符号,可以设置某些自定义的特殊组和来表达感情,如输入:),则会自动发送“XXX向大家做了个笑脸”
5. Client 段增加某些常用话语,可以对其中某些部分进行“姓名替换”,例如,输入/ClientA/welcome,则会自动发送“ClientA大侠,欢迎你来到咱们的聊天室”
Client.c源文件

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <stdlib.h>
#include <sqlite3.h> 
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

#define PORT  9999

char myName[20];        // 保存用户名
char msg1[1024];        // 保存聊天信息

sqlite3 * database;

int flag1 = 0;          // 线程退出的判断条件(不退出)
int flag2 = 0;          // 文件传输确认信号(无接收)
int flag3 = 0;          // 存在文件接收请求的判断(不存在)
int flag4 = 0;          // 本地存储是否被禁言(未被禁言)

// 协议
struct Msg
{
    char msg[1024];         // 消息内容
    int  cmd;               // 消息类型
    char filename[50];      // 保存文件名
    char toname[20];        // 接收者姓名
    char fromname[20];      // 发送者姓名
    int  sig;               // 用户状态(0:管理员、1:普通用户、2:被禁言)
};

struct Msg msg;     // 全局变量两个线程共享

// 注册/登录界面
void interface1()
{
    system("clear");
    printf ("\t*************************** 网络聊天室 *****************************\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                    1、 注册                                      *\n");                               
    printf ("\t*                    2、 登录                                      *\n");
    printf ("\t*                    q、 退出                                      *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                 BY szw           *\n");
    printf ("\t********************************************************************\n\n");
    printf ("\t***** 请输入命令: ");

}

// 普通用户界面
void interface2()
{
    system("clear");
    printf ("\t*************************** 网络聊天室 *****************************\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                    1、 查看当前在线人数                          *\n");                               
    printf ("\t*                    2、 进入群聊界面                              *\n");
    printf ("\t*                    3、 进入私聊界面                              *\n");
    printf ("\t*                    4、 查看聊天记录                              *\n");
    printf ("\t*                    5、 文件传输                                  *\n");
    printf ("\t*                    6、 更改密码                                  *\n"); 
    printf ("\t*                    7、 在线注销                                  *\n"); 
    printf ("\t*                    Q、 退出聊天室 返回登录界面                   *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                    BY szw        *\n");
    printf ("\t********************************************************************\n\n");
    printf ("\t***** 请输入命令: ");
}

// 管理员界面
void interface3()
{
    system("clear");
    printf ("\t*************************** 网络聊天室 *****************************\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                    1、 查看当前在线人数                          *\n");                               
    printf ("\t*                    2、 进入群聊界面                              *\n");
    printf ("\t*                    3、 进入私聊界面                              *\n");
    printf ("\t*                    4、 查看聊天记录                              *\n");
    printf ("\t*                    5、 文件传输                                  *\n");
    printf ("\t*                    6、 更改密码                                  *\n"); 
    printf ("\t*                    7、 在线注销                                  *\n"); 
    printf ("\t*                    8、 管理员界面                                *\n");  
    printf ("\t*                    Q、 退出聊天室 返回登录界面                   *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                                  *\n");
    printf ("\t*                                                    BY szw        *\n");
    printf ("\t********************************************************************\n\n");
    printf ("\t***** 请输入命令: ");
}

// 用来保存收到的聊天信息
void keep_msg(char * msg1)
{
    // 打开数据库
    int ret = sqlite3_open("Histroy.db", &database);
    if (ret != SQLITE_OK)
    {
        printf ("\t打开数据库失败\n");
        return;
    }

    // 往histroy表中添加信息
    char buf[100];
    char *errmsg = NULL;
    sprintf (buf, "insert into histroy values('%s','%s','%s')",msg.fromname,msg.toname,msg1);
    ret = sqlite3_exec(database, buf, NULL, NULL, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf ("\t数据库操作失败:%s\n", errmsg);
        return;
    }
}

// 接收文件
void receive()
{
    printf ("\n\t正在接收文件.....\n");
    int fd2 = open(msg.filename, O_WRONLY|O_CREAT, 0777);
    if (fd2 == -1)
    {
        perror ("open fd2");
        return;
    }
    write (fd2, msg.msg, 1023);
    close (fd2);
}

// 用来监听收到的信息
void *readMsg(void *v)
{

    int socketfd = (int)v;
    while(1)
    {
        if (flag1 == 1)         // 判断线程的退出条件
        {
            flag1 = 0;          // 重置线程退出条件
            pthread_exit(NULL);
        } 
        read (socketfd, &msg, sizeof(msg));

        switch(msg.cmd)
        {
            case 9001:       // 群聊
                sprintf (msg1, "收到一条来自%s的群消息:\n\t%s", msg.fromname,msg.msg);
                printf ("\n\n\t%s\n", msg1);
                printf ("\n\t回车键返回  \n");
                keep_msg (msg1);
                break;
            case 9002:       // 私聊
                printf ("\n\t%s 发来一条消息:\n\t%s\n", msg.fromname, msg.msg);
                sprintf (msg1,"%s 向 %s 发送一条信息:\n\t%s",msg.fromname, msg.toname, msg.msg);
                printf ("\n\t回车键返回  \n");
                keep_msg (msg1);
                break;
            case 9003:      // 处理发送失败
                sleep(3);
                printf ("\n\t用户不在线或不存在,发送失败\n");
                printf ("\n\t回车键返回  \n");
                break;
            case 9004:      // 是否存在文件接收确认信号
                printf ("\n\n\t收到一条信息,输入任一字符进行回复:");
                fflush(stdout);
                flag3 = 1;
                break;  
            case 9005:      // 文件传输请求被拒绝
                printf ("\n\t您发送的文件传输请求已被拒绝\n");
                printf ("\n\t回车键返回  \n");
                break;
            case 9006:      // 文件传输请求已通过
                printf ("\n\t您发送的文件传输请求已通过,请打开文件传输界面进行文件传输\n");
                printf ("\n\t回车键返回  \n");
                break;
            case 9007:      // 接收文件
                if (flag2 != 1)
                    printf ("\n\t已成功拦截 %s 给您发送的文件\n", msg.fromname);
                else
                    receive();
                break;
            case 9008:      // 文件传输完成   
                printf ("\n\t%s 给您发送的文件已全部接收完毕,请及时查看\n", msg.fromname);
                printf ("\n\t回车键返回  \n");
                flag2 = 0;  // 重置文件传输确认信号
                break;
            case 9009:      // 密码修改成功
                printf ("\n\t密码修改成功!\n");
                sleep(1);
                break;
            case 9010:      // 密码输入有误
                printf ("\n\t密码输入有误,修改失败\n");
                usleep(1500000);
                break;  
            case 9011:      // 收到禁言信号
                printf ("\n\t您已被管理员禁言,将无法发送群聊信息\n");
                printf ("\n\t回车键返回  \n");
                flag4 = 1;
                break;
            case 9012:      // 收到结除禁言信号
                printf ("\n\t您已被管理员解除禁言\n");
                printf ("\n\t回车键返回  \n");
                flag4 = 0;
                break;
            case 9013:      // 收到被踢出信号
                printf ("\n\t您已被管理员踢出,即将退出聊天室....\n");
                //sleep (2);
                flag1 = 1; 
                break;
        }
        usleep(400000);
    }
}

// 查看当前在线人数
void display (int socketfd)
{
    msg.cmd = 1;

    write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求

    usleep(100000);
    printf ("\n\t当前在线人数为:%d\n", msg.cmd);
    printf ("\n\t回车键返回  \n");
    getchar();
}

// 退出聊天室,返回登录界面
void quit_chatroom (int socketfd)
{
    msg.cmd = 10;
    strcpy (msg.fromname, myName);
    write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送退出信号
}

// 进入群聊界面
void chat1(int socketfd)
{
    if (flag4 == 1)
    {
        printf ("\n\t您已被管理员禁言,无法发送群聊信息...\n");
        return;
    }
    msg.cmd = 2;
    strcpy (msg.fromname, myName);
    strcpy(msg.toname, "all");

    printf ("\n\t请输入您要发送的内容:\n\t");
    scanf ("%s",msg.msg);
    getchar();

    write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求

    printf ("\n\t发送完成,等待处理结果.....\n");
//  usleep (500000);
}

// 进入私聊界面
void chat2(int socketfd)
{   
    msg.cmd = 3;
    strcpy (msg.fromname, myName);

    printf ("\n\t请输入您要发送的对象:\n\t");
    scanf ("%s",msg.toname);
    getchar();

    printf ("\t请输入您要发送的内容:\n\t");
    scanf ("%s",msg.msg);
    getchar();

    write (socketfd, &msg, sizeof(struct Msg));  //向服务器发送请求

    printf ("\n\t发送完成,请稍候.....\n");
    usleep (500000);
}

// 打印群聊历史记录
void chat1_hst()
{
    system("clear");
    printf ("\t*************************** 网络聊天室 *****************************\n\n\n");
    printf ("\t群聊历史记录:                                                      \n");

    // 打开数据库
    int ret = sqlite3_open("Histroy.db", &database);
    if (ret != SQLITE_OK)
    {
        printf ("\t打开数据库失败\n");
        return;
    }

    // 获取histroy表中的信息
    char *errmsg = NULL;
    char **resultp = NULL;
    int nrow, ncolumn;
    char *sql = "select * from histroy";
    ret = sqlite3_get_table(database, sql, &resultp, &nrow, &ncolumn, &errmsg);
    if (ret != SQLITE_OK)
    {
        printf ("数据库操作失败:%s\n", errmsg);
        return;
    }
    int i;
    for (i = 1+ncolumn; i < (nrow+1)*ncolumn; i+=ncolumn)
    {
        if(strcmp(resultp[i], "all") ==
C语言网络编程聊天室是一个基于TCP/IP协议的聊天程序,可以在Linux操作系统上使用。它可以通过socket和多线程实现,也可以使用UDP或epoll来处理高并发。该聊天室可以支持多个客户端与服务器进行实时通信,并允许用户加入和退出不同的聊天室。 实现C语言网络编程聊天室的主要步骤包括: 1. 需求分析:确定聊天室的功能需求。 2. 学习TCP/IP协议:理解C/S模型、socket编程的常规步骤以及阻塞与非阻塞socket等概念。 3. 文件操作和数据库:学习如何进行文件操作和数据库的操作,以便存储聊天记录和用户信息等。 4. 实现思路:考虑如何设计服务器和客户端之间的通信方式,以及如何处理多个客户端的并发连接。 5. 编写代码:根据需求和思路,编写服务器和客户端的代码。 6. 运行测试:运行服务器和客户端程序,检查是否能够实现实时通信和聊天室的基本功能。 如果要退出聊天室,可以使用exit_chatroom函数。该函数会遍历聊天室列表,找到用户所在的聊天室,并将用户从聊天室中移除。如果用户未加入聊天室,则会返回相应的提示信息。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [C语言练手项目--C 语言编写聊天室](https://blog.csdn.net/qq_38880380/article/details/84979553)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [网络编程基础,纯C语言实现聊天室(附源代码)——从铁矿到钢铁的打造](https://blog.csdn.net/weixin_43164603/article/details/107301548)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值