0
点赞
收藏
分享

微信扫一扫

基于ubantu操作系统下,利用tcp+多线程实现聊天室基本功能(一)

                                        第一部分:总览

项目名称:菜鸡聊天室

操作系统:linux 软件:vscode 实现方式:tcp+多线程 数据存储方式:sqlite3数据库

这个聊天室项目的第一版本,基本实现了同时进行多个客户端的注册、登录、会员申请、禁言等基本功能,具体功能如下图:

图(一)

        在这个版本的聊天室中,主要分为服务器和客户端两个部分,服务器中主要负责接收客户端传过来的结构体,再将操作之后的结构体传回给对应的客户端。客户端则主要负责发送信息,并且做出对应的判断和处理操作。

 下面是实现效果图(分别是会员登录和普通用户登录)

左边是服务器右边是客户端

下面是代码部分:

结构体:

#pragma once//为了避免同一个头文件被包含(include)多次

struct message
{
    int action;//标志位
    int vip;//是否为vip
    int flags;//标志位
    int talk;//是否可以说话

    char name[20];//姓名
    char passwd[20];//密码
    char friend[20];//好友姓名
    char msg[100];//消息内容
    char io_name[20];//文件名
};
typedef struct message Msg;

服务器端:

main.c  文件

主要负责服务器tcp的链接,创建一个线程函数负责进行之后对传过来的结构体进行处理

#include"serever.h"
#include"Msg.h"
int c1=0;
int c2=0;
int c3=0;
int c4=0;
sqlite3 *ppdb;
sqlite3 *ppdb2;
long sockfd;
FILE *fp;
int main(int argc, char const *argv[])
{
    signal(SIGINT,serever_exit);
    createsqlite();
    createsqlite_chatting_records();

    socklen_t c_size; 
    long cfd;
    int r_n;
    int w_n;
    pthread_t id;

    struct sockaddr_in s_addr;
    struct sockaddr_in c_addr;
    

    if((sockfd=socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,0))<0)
        {
            perror("socket");
            exit(1);
        }
    printf("socket  success!\n");
    s_addr.sin_family=AF_INET;
    s_addr.sin_port=htons(8888);//端口号
    //s_addr.sin_addr.s_addr=inet_addr("192.168.193.129");
    s_addr.sin_addr.s_addr=htons(INADDR_ANY);//绑定任意网卡
    int opt=1;
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));//设置套接字可以重复使用套接字
    if(bind(sockfd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr_in))!=0)
        {
            perror("bind");
            exit(1);
        }
    printf("bind success!\n");
    if(listen(sockfd,20)!=0)
        {
            perror("listen");
            exit(1);
        }
    printf("listen success!\n");
    while(1)
        {
            c_size =sizeof(struct sockaddr_in);
            cfd=accept(sockfd,(struct sockaddr*)&c_addr,&c_size);
            if(cfd<0)
                {
                    if(errno!=EAGAIN&&errno !=EWOULDBLOCK&&errno!=EINTR)//保存系统调用产生的错误值
                        {
                            perror("accept");
                            exit(1);
                        }
                    continue;   
                }
            printf("info client:ip=%s,port=%d\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port));
            
            if(pthread_create(&id,NULL,thread_read,(void*)cfd)<0)//创建线程
                {
                    perror("thread error");
                    exit(1);
                }
        }
     
    return 0;
}

 以下是头文件

#ifndef   _client_H_
#define  _client_H_
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/un.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<sys/wait.h>
#include<unistd.h>
#include <sqlite3.h>
#include<pthread.h>
#include<sys/stat.h>
#include <fcntl.h>

pthread_mutex_t mutex ;

struct online
{
    int cfd;
    char name[20];
    struct online *next;
};

void *insert_link(struct online*new_user);
int find_fd(char *friend);//私聊时查看好友是否在链表内(是否在线)
char*find_self(int cfd);//查看在链表内的自己的名称(是否在线)
int callback1(void *arg,int ncolumn,char**f_value,char**f_name);//检查姓名
int callback2(void *arg,int ncolumn,char**f_value,char**f_name);//检查密码
int callback3(void *arg,int ncolumn,char**f_value,char**f_name);//检查vip
int callback4(void *arg,int ncolumn,char**f_value,char**f_name);//检查是否可以说话

void* createsqlite();//创建用户信息数据库

void* createsqlite_chatting_records();//创建用户聊天记录数据库

void serever_exit(int sig);//退出信号

void *thread_read(void *arg);//服务器接受客户端信息

#endif

 serever.c文件

********************************************(保密)

客户端:

main.c

负责tcp网络的链接,并且创建线程函数实现聊天室功能

#include"client.h"
#include"Msg.h"
int loged=1;
FILE *fp;
int main(int argc, char const *argv[])
{
    if(argc!=3)
        {
            printf("please input serever ip and port!\n");
        }
    int r_n;
    long sockfd;
    struct sockaddr_in s_addr;
    pthread_t id;
    char cmd[10]={0};
    char cmd2[10]={0};

    fp=fopen("./chat_msg.txt","r");
    if(NULL == fp)
        {
            perror("open");
            return -1;
        }
    pthread_mutex_init(&mutex,NULL);
    Msg *pmsg=(Msg*)malloc(sizeof(Msg));

    if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
        {
            perror("socket");
            exit(1);
        }
    //printf("socket success!\n");
    s_addr.sin_family=AF_INET;
    s_addr.sin_port=htons(atoi(argv[2]));//指定服务器端口号
    s_addr.sin_addr.s_addr=inet_addr(argv[1]);//指定服务器ip地址

    if(connect(sockfd,(struct sockaddr*)&s_addr,sizeof(struct sockaddr))!=0)
        {
            perror("connect");
            exit(1);
        }
    //printf("connect success!\n");
    //system("clear");

    pthread_create(&id,NULL,thread_read,(void*)sockfd);//父线程

    printf("欢迎来到菜鸡聊天室\n");
    while(1)
        {
            //main_menu(cmd);
            sleep(2);
            system("clear");
            printf("---------------------------------------------------------\n\n");
            printf("\t    选项:(请输入文字前面的选项)\n\n");
            printf("\t        1.注册(reg):\n\n");
            printf("\t        2.登陆(log):\n\n");
            printf("\t        3.退出(exit):\n\n");
            printf("---------------------------------------------------------\n\n");
            printf("请输入选项\n");
            scanf("%s",cmd);
            system("clear");
            if(strcmp(cmd,"1")==0)//注册
                {
                    client_reg(pmsg, sockfd);
                }
            if(strcmp(cmd,"2")==0)//登陆
                {
                    client_log(pmsg,sockfd);

                    while(1)
                    {
                        if(loged == 2)//普通用户登陆之后的操作
                            {
                                //menu(cmd2);  
                                sleep(2);
                                system("clear");
                                printf("******************************************\n");
                                printf("\t    选项:(请输入文字前面的选项)\n\n");
                                printf("\t        1.私聊(chat):\n\n");
                                printf("\t        2.群聊(allchat):\n\n");
                                printf("\t        3.申请成为会员(apply_vip):\n\n");
                                printf("\t        4.查看聊天记录(read):\n\n");
                                printf("\t        5.查看在线人数(look):\n\n");
                                printf("\t        6.返回注册界面(break):\n\n");
                                printf("******************************************\n\n");
                                scanf("%s",cmd2);                            
                                if(strcmp(cmd2,"1")==0)//私聊
                                    {
                                        client_chat(pmsg,sockfd);
                                    }
                                if(strcmp(cmd2,"2")==0)//群聊
                                        {
                                            client_allchat(pmsg,sockfd);
                                        }
                                if(strcmp(cmd2,"3")==0)//申请成为管理员
                                        {
                                            client_apply_vip(pmsg,sockfd);  
                                        }
                                if(strcmp(cmd2,"4")==0)//查看聊天记录
                                        {
                                            client_read(pmsg,sockfd);
                                        }
                                if(strcmp(cmd2,"5")==0)//查看在线人数
                                    {
                                        client_look(pmsg,sockfd);
                                    }
                                if(strcmp(cmd2,"6")==0)//退出
                                        {
                                            client_break(pmsg,sockfd);
                                            break;
                                        }
                            }
                        if(loged == 3)//vip用户登陆之后的操作
                            {
                                while(1)
                                {
                                   //vipmenu(cmd2);
                                    sleep(2);
                                    system("clear");
                                    printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n");
                                    printf("\t    $选项$:(请输入文字前面的选项)\n\n");
                                    printf("\t        $1.私聊$(chat):\n\n");
                                    printf("\t        $2.群聊$(allchat):\n\n");
                                    printf("\t        $3.禁言$(stop):\n\n");
                                    printf("\t        $4.解除禁言$(over_stop):\n\n");
                                    printf("\t        $5.踢人下线$(out):\n\n");
                                    printf("\t        $6.查看聊天记录(read):\n\n");
                                    printf("\t        $7.文件传输(io):\n\n");
                                    printf("\t        $8.查看在线人数(look):\n\n");
                                    printf("\t        $9.返回注册界面(break):\n\n");
                                    printf("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n");
                                    scanf("%s",cmd2);
                                    if(strcmp(cmd2,"1")==0)//vip 功能私聊
                                        {
                                            client_vipchat(pmsg,sockfd);   
                                        }
                                    if(strcmp(cmd2,"2")==0)//vip 功能群聊
                                        {
                                            client_vipallchat(pmsg,sockfd);                                      
                                        }
                                    if(strcmp(cmd2,"3")==0)//vip 功能 禁言
                                        {
                                            client_stop(pmsg,sockfd);                                          
                                        }
                                    if(strcmp(cmd2,"4")==0)//vip 功能 解除禁言
                                        {
                                            client_overstop(pmsg,sockfd);
                                        }
                                    if(strcmp(cmd2,"5")==0)//vip 功能 踢人下线
                                        {
                                            client_out(pmsg,sockfd);                                           
                                        }
                                    if(strcmp(cmd2,"6")==0)//vip 功能 查看聊天记录
                                        {
                                            client_vipread(pmsg,sockfd);
                                        }
                                    if(strcmp(cmd2,"7")==0)//文件传输
                                        {
                                            printf("功能正在完善,请等待下次更新...");
                                            //client_vip_io(pmsg,sockfd);
                                        }
                                    if(strcmp(cmd2,"8")==0)//查看在线人数
                                        {
                                            client_look(pmsg,sockfd);
                                        }
                                    if(strcmp(cmd2,"9")==0)//返回上一级界面
                                        {
                                            client_break(pmsg,sockfd);
                                            break;
                                        }
                                }
                            }
                        if(loged == 0)
                            {
                                loged = 1;
                                break;
                            }
                    }
                }
            if(strcmp(cmd,"3")==0)//退出系统
                {
                    client_exit();
                }
        }
   
    if(fclose(fp) == EOF)
        {
            printf("关闭失败\n");
            return -1;
        }
    return 0;
}

client.h 文件

#ifndef   _client_H_
#define  _client_H_
#include "Msg.h"
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<stdlib.h>
#include<errno.h>
#include<sys/un.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<signal.h>
#include<unistd.h>
#include<pthread.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

pthread_mutex_t mutex ;

void *thread_read(void *);//子线程读
void client_reg(Msg *pmsg, long sockfd);//注册
void client_log(Msg*pmsg,long sockfd);//登陆
void client_chat(Msg*pmsg,long sockfd);//私聊
void client_allchat(Msg*pmsg,long sockfd);//群聊
void client_apply_vip(Msg*pmsg,long sockfd);//申请成为管理员
void client_read(Msg*pmsg,long sockfd);//查找聊天记录
void client_break(Msg*pmsg,long sockfd);//退出

void client_vipchat(Msg*pmsg,long sockfd);//vip 功能私聊
void client_vipallchat(Msg*pmsg,long sockfd);//vip 功能群聊
void client_stop(Msg*pmsg,long sockfd);//vip 功能 禁言
void client_overstop(Msg*pmsg,long sockfd);//vip 功能 解除禁言
void client_out(Msg*pmsg,long sockfd);//vip 功能 踢人下线
void client_vipread(Msg*pmsg,long sockfd);//vip 功能 查找聊天记录
//void client_vip_io(Msg*pmsg,long sockfd);//vip 功能 文件传输
void client_look(Msg*pmsg,long sockfd);//查看在线人数
void client_exit();//退出

// void main_menu(int cmd);//主菜单
// void menu(int cmd2);//普通用户菜单
// void vipmenu(int cmd2);//vip用户菜单

#endif

client.c文件

********************************************(保密)

 

举报

相关推荐

0 条评论