万人聊天室制作

本文介绍了一个基于TCP的聊天室实现,包括服务器和客户端的代码。用户通过客户端连接服务器,经过验证码验证后进入群聊,可以发送和接收消息。服务器负责转发消息并处理用户进出群的反馈。程序还包含时间戳显示和退出评价功能,提供了一种简单的多人交互体验。
摘要由CSDN通过智能技术生成

今天分享一个基于tcp通信的万人聊天室,非常的有意思,让我们一起来看看吧,首先我们做聊天室需要一个客户端一个服务器,

1.服务器用于为客户端提供服务,默默的守护在后台,给每一位客户提供服务,将群聊的每一位成员发送的消息转发给所有人,当然也可以看到一些信息。比如显示是哪一位客户登录了进来,以及当有成员离开群聊的时候会提示一个反馈信息(相当于客户给开发者的一些建议,把自己想对开发者的话发送给服务器,这条消息是不会发送给其他群友的!)

让我们来看看整体的的效果吧,左边是服务器,右边是三个客户

首先我们得先打开服务器件,然后运行客户端之后可以选择进入群聊还是退出,

如果是进入群聊的话,服务器会给客户端发送一个随机生成的五位数验证码,客户有两次机会,输错验两次证码就会跳转界面

输错次数达到上限之后跳转,重新选择进入群聊

进群之后系统提示给自己的群聊群一个昵称,然后进入群聊,服务器会打印出来是谁进入的群聊

进入后可以自由群聊,在每一位额群员的接受消息的后面会打印出来接收到消息的时间,如图一效果展示

群聊结束后发送quit的退出指令,服务器就会相应,给客户发送评价反馈

如果有评价就会打印出客户的评价消息,如果没有就是潇洒的离开,这条反馈消息是不会转发给所有的群友的,只是客户端和服务端的一次沟通,离开和加入群聊人数也会相应的增加减少,

好了说了这么多让我们来看看源码吧

首先来看看服务器的代码怎么写

第一个是服务端的.h文件,第二个是服务端的.c文件

#ifndef __CHATROOM__HH__
#define __CHATROOM__HH__
//头文件
#include<sys/wait.h>
#include<stdio.h>
#include<unistd.h>
#include <sys/types.h>
#include<time.h>
#include<stdlib.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
#include<pthread.h>
#include<semaphore.h>
#include<signal.h>
#include<sys/ipc.h>
#include <sys/msg.h>
#include <arpa/inet.h>
#include <sys/socket.h> 
#include <netinet/in.h>
#include <netdb.h>
#include <sys/select.h>

//定义客户端结构体,存放客户端套接字
 typedef struct client
 { 
    int cidstr[10];//存放客户端套接字
    int cidstrnum;//人数
 }client;

//客户界面
    void StuDesk();
//客户群聊
    void qunliao();
//客户进群验证
    int yanzheng();
//聊天界面
    void uiinit();

#endif
#include"touwenjian.h"

 client clients={0};

void* pthread_fun(void* arg)
{
    //强转赋值给cid
    int* p=(int*)arg;
    int cid=*p;
    //发送内容数组
    char sendbuf[128]={0};
    //接收内容数组
    char recvbuf[128]={0};
    //读取客户端发来的名字
    read(cid,recvbuf,sizeof(recvbuf));
    //定义名字数组承接客户端发来的名字
    char name[128] = {0};
    strcpy(name,recvbuf);
      //打印哪位用户上线
    printf("%s:上线了\n",name);
    char buf[128]="欢迎";
       //把用户名追加到欢迎后
    strcat(buf,name);
    strcat(buf,"加入群聊\n");
     
    for (int i = 0; i < 10; i++)
    {
        if (clients.cidstr[i]==0)
        {   //如果没有人就退出
            continue;
        }
        write(clients.cidstr[i],buf,sizeof(buf));
    }
    char kaitouname[128] = {0};
    //将用户名和:放在最前面
    strcpy(kaitouname,name);
    strcat(kaitouname,":");
    bzero(recvbuf,sizeof(recvbuf));//清空接收内容
    while(strncmp("quit",recvbuf,4))//退出
    {
        bzero(recvbuf,sizeof(recvbuf));//清空接收内容
        if(read(cid,recvbuf,sizeof(recvbuf)))//返回值非0成功读取客户发的内容
        {
            bzero(sendbuf,sizeof(sendbuf));//清空发送内容
            strcpy(sendbuf,kaitouname);//将名字和:追加
             
             //生成时间信息
            time_t tm1 = 0;
            time(&tm1);
            struct tm* localtm;
            localtm = localtime(&tm1);
            char timestr[128] = {0};

            //将时间信息(int 型)转化成字符串型存入timestr 
            //主要功能是把格式化的数据写入某个字符串中
            sprintf(timestr,"\t\033[33m\033[32m接收时间[周%d时%d分%d秒%d]\033[0m\n",localtm->tm_wday,localtm->tm_hour,localtm->tm_min,localtm->tm_sec);
           //将接收数组的\n剔除
              char* huanhangp = strstr(recvbuf,"\n");
               *huanhangp=0;     
            strcat(sendbuf,recvbuf);//将客户发的内容追加到后面
            strcat(sendbuf,timestr);//将时间信息追加到 姓名:内容 后
            //群发消息
            for(int i = 0;i<10;i++)
            {    //遍历发送
                if(clients.cidstr[i] == cid || clients.cidstr[i] == 0)
                {
                    continue;
                }
               write(clients.cidstr[i],sendbuf,sizeof(sendbuf));
            }
        }
    }
    for(int i = 0;i<10;i++)
    {
        if(clients.cidstr[i]==cid)//避免发给自己
        {
            clients.cidstr[i] = 0;
            break;
        }
    }
  
    clients.cidstrnum--;
    char likai[128];
    if(read(cid,likai,sizeof(likai)))
    {
        printf("\033[33m\033[32m%s:下线了,并说道%s\033[0m\n\n",name,likai);
    }
   else
    {
        printf("\033[33m\033[33m%s下线了,啥也没说只是潇洒的离开\033[0m\n",name);
    }
    close(cid);
    printf("\n\033[0;43m现在有%d个人在线\033[0m\n\n",clients.cidstrnum);
}

int main(int argc,char* argv[])
{

    //1.建立套接字
    int sid=socket(AF_INET,SOCK_STREAM,0);
    if (sid<0)
    {
        perror("套接子建立失败\n");
        return -1;
    }
    
    //定义服务端地址结构体
    struct sockaddr_in faddr={0};
    faddr.sin_family=AF_INET;
    faddr.sin_addr.s_addr=inet_addr("192.168.1.0");
    faddr.sin_port=htons(11000);

    //2.绑定服务端
    if(bind(sid,(struct sockaddr*)&faddr,sizeof(faddr)))
    {
        printf("绑定失败\n");
    }
    else
    {
        printf("绑定成功\n");
    }

    //3.监听
    if(listen(sid,10))
    {
        perror("listen is failed\n");
        return -1;
    }
    else
    {
        printf("监听成功\n");
    }

    //定义客户端地址结构体
    struct sockaddr_in caddr = {0};
    int size = sizeof(caddr);

    //定义线程id
    pthread_t tid;
    //定义客户端的ip
    char ip[16] = "";
    //4.链接客户端
    while (1)
    {
        int rid=accept(sid,(struct sockaddr*)&caddr,&size);
        if (rid>0)
        {
            for(int i = 0;i < 10;i++)
            {
                if(clients.cidstr[i] == 0)
                {
                    clients.cidstr[i] =rid;
                    break;
                }
            }
            printf("%s:%d:连接成功\n",inet_ntop(AF_INET,&caddr.sin_addr.s_addr,ip,16),ntohs(caddr.sin_port));
            pthread_create(&tid,NULL,pthread_fun,(void*)&rid);
            clients.cidstrnum++;
            printf("\n\033[0;42m现在有%d个人在线\033[0m\n",clients.cidstrnum);           
        }
    }
    //关闭套接字
    close(sid);

    return 0;

}

然后我么看到的是客户端的.c文件

#include"touwenjian.h"
//群聊函数

void qunliao()
{
    //1.建立套接字
    int cid=socket(AF_INET,SOCK_STREAM,0);
    if (cid<0)
    {
        perror("create socket failed\n");
        return ;
    }
    //2.客户端链接服务端 客户端这边ip和端口写入结构体
    struct sockaddr_in caddr={0};
    caddr.sin_family=AF_INET;
    caddr.sin_addr.s_addr=inet_addr("192.168.1.0");
    caddr.sin_port=htons(11000);
    
    char name[128]={0};
    //2.连接客户端
    if (connect(cid,(struct sockaddr*)&caddr,sizeof(caddr)))
    {    //失败返回非0抱错
        perror("连接服务器失败\n");
        return ;
    }
    else
    {
        printf("\n\033[33m\033[31m连接服务器成功!\033[0m\n\n");
        printf("\033[33m\033[36m请给你的聊天号取一个炫酷的昵称:\033[0m");
        scanf("%s",name);
        write(cid,name,strlen(name)+1);
    }
    //建立rest文件集合
    fd_set rset={0};
    char sendbuf[1024]="";//发送(键盘)
    char recvbuf[1024]="";//接收
    //监控键盘和套接字
    while (strncmp("quit",sendbuf,4))
    {
        //把标准输入设备加入集合
        FD_SET(STDIN_FILENO,&rset);
        //把套接字加入集合
        FD_SET(cid,&rset);
        select(cid+1,&rset,NULL,NULL,NULL);
        if (FD_ISSET(STDIN_FILENO,&rset))
        {   
            bzero(sendbuf,sizeof(sendbuf));
            read(STDIN_FILENO,sendbuf,sizeof(sendbuf));
            write(cid,sendbuf,strlen(sendbuf));
        }
        if (FD_ISSET(cid,&rset))
        {
            bzero(recvbuf,sizeof(recvbuf));
            read(cid,recvbuf,sizeof(recvbuf));
            printf("%s",recvbuf);
        }
    }
    char likai[128];
    bzero(likai,sizeof(likai));
    bzero(sendbuf,sizeof(sendbuf));
    system("clear");
    printf("\n\033[33m\033[31m是否直接退出群聊选择\033[0m yes \033[33m\033[31m直接退出\n选择\033[0m no \033[33m\033[31m则发表意见\n\033[0;42myes/no\033[0m\n");
      scanf("%s",sendbuf);
    if(strncmp("yes",sendbuf,3))
    {
        printf("请发表你对该群的看法\n");
        scanf("%s",likai);
        write(cid,likai,sizeof(likai));
    }
    else
    {
        close(cid);
    }
    //关闭套接字

    close(cid);
    return ;
}
//进群验证函数
int yanzheng()
{
          system("clear");
      AAA:
          srand(time(NULL));
          int yanzhen=rand()%100000;//随即生成验证码(最大999999)
          int shuyan;//输入验证码匹配
          int flg=0;
          int ass=0;
                          
          printf("\n");
          printf("\n\033[33m\033[32m等待系统发送进群验证码>>>>>\033[0m\n");
          sleep(3);
          printf("\033[33m\033[33m您的验证码是:%d\033[0m\n",yanzhen);
       ppp:  
           sleep(1);
           printf("请输入系统发送的验证码:");scanf("%d",&shuyan);
             printf("\n\t\t\t\033[0;42m正在验证.............\033[0m\n");
           sleep(2);
           if(shuyan==yanzhen)
           {
               sleep(1);
               printf("\n\033[33m\033[32m验证码正确,等待连接接进群.........\n\n");
                sleep(3);
                return 0;
           }
           else 
           {
                flg++;
                if(flg==2)
                {
                    printf("\n\t\033[33m\033[33m进群验证码连续输入错误两次,无法进入,请做出以下选择\033[0m\n");
                    sleep(2);
                    system("clear");
                    printf("\n\t\033[33m\033[33m进群验证码连续输入错误两次,无法进入,请做出以下选择\033[0m\n");
                    sleep(1);
                      printf("\t\t=================================\n");
                      printf("\t\t*        [1]直接退出到主界面    *\n");
                      printf("\t\t*        [2]重新选择接收验证码  *\n");
                      printf("\t\t=================================\n");
                      printf("\t\t请输入您的选择>>");
                    scanf("%d",&ass);
                    if(ass==1)
                    {
                      printf("\033[33m\033[32m您选择直接退出到主界面,稍等\033[0m\n");
                      sleep(2);
                      return 1;
                    }
                    if(ass==2)
                    {
                      printf("\033[33m\033[32m您选择重新接收验证码,请稍等\033[0m\n");
                      sleep(2);
                      goto AAA;
                    }
                }
                sleep(1);
                printf("\n\033[33m\033[31m\t红色警告!进群验证码输入错误一次,输入错误两次则禁止进入该群!\n\t\t\t\t请重新输入验证码!\n\n");
                sleep(1);
                goto ppp;
           }
}

然后这里是ui.c文件

#include"touwenjian.h"
void StuDesk()
{ 
    printf("\033[33m\033[33m*************************************************************\n");
    printf("*************************************************************\n");
    printf("*                 ==欢迎各位首富来此交流==                  *\n");
    printf("*              =========选择界面============                *\n");
    printf("*                                                           *\n");
    printf("*\033[33m\033[37m                      [1]进群交流                          *\n");
    printf("*                                                           *\n");
    printf("*                                                           *\n");
    printf("*                                                           *\n");
    printf("*                                                           *\n");
    printf("*                      [0]退出                              *\n");
    printf("*                                                           *\n");
    printf("\033[33m\033[33m*************************************************************\n");
    printf("*************************************************************\n");
    printf("\033[33m\033[37m请输入你的选择:\n");
    printf(">>>>");
 
}

接下来是最后的是main函数

#include"touwenjian.h"
int main(int argc,char* argv[])
{
    int add=0;//客户选择变量
    do
    {
        system("clear");
        StuDesk();//客户界面
        scanf("%d",&add);
        switch(add)
        {
        case 1: system("clear");
                 int add=yanzheng();//验证进群函数
                  if(add==1)
                  {
                      break;
                  }
                system("clear");
                 qunliao();//群聊函数
                 break;
        case 2: system("clear");
                 
                 break;
        case 0: printf("感谢使用====群聊系统==== 已退出\n");
                break;
        default:printf("没有此选项,请重新输入您的选项\n");
                break;
        }
    } while(add);
}

到这里的话代码展示和效果展示就到一段落了,主要是实现了一个群的功能,在群聊的基础上添加了一些其他的小功能,让整个程序的效果更优化了,比如显示时间,离场反馈,入场简介,入场验证码的功能,好了,快动手试试吧,快拉上你的小伙伴在自己写的群聊里畅所欲言吧😁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值