• linux系统下实现聊天室


    目标:

     linux系统下实现聊天室

    (1)在Linux系统下,使用TCP协议套接字编程;

    (2)服务器应具有处理多个客户端连接能力(设定最大连接数,如5个);

    (3)具有群发和私聊的能力;

    (4)过程描述

    客户端:连接服务器后,应能接收服务器发来信息并处理的能力,当收到聊天信息时,显示群发或私聊、信息发送客户及发送的信息,当收到客户加入或退出时,显示客户登录或退出,并更新客户列表;每次可选择群发或私聊,群发时将键盘输入信息发送给服务器,私聊时,选择私聊客户并将输入信息发送给服务器。选择退出时,结束进程或线程,关闭程序。

    服务器:为每个客户连接创建一个进程或线程,处理客户信息,当有新客户加入或有客户退出时,将客户加入或退出信息发送给每个客户端;当收到某客户的群发信息时,将信息转发给每个客户,当收到客户私聊时将信息转发给私聊客户;客户退出时关闭相应的进程或线程。



    二、系统设计

    1、数据结构设计

    A.定义在线客户列表数据结构ClientList。

    typedef struct ClientList 

    {

    char name[NAME_LEN];

    int socketFd;

    }CLIENTLIST;

    说明:

    name为客户端名称;socketFd是服务器为客户端分配的通信 socket套接字标识符;

    B.定义客户与服务器之间交互信息格式结构Message。

    typedef struct Message

    {

    char fromUser[NAME_LEN];

         int  fromUserLocate;

    int  type;

    int  sendUserLocate;

    char message[MSG_LEN];

    CLIENTLIST clientList[MAX_CLIENT];

    }MESSAGE;

    说明:

    fromUser为客户端名称;fromUserLocate为该客户端在在线客户列表 里的位置;type为消息的类型(包括群发、私聊、登录、退出); sendUserLocate为私聊对象在客户端列表中的位置(仅在type为私 聊类型是有效);message为发送的消息内容,clientList为在线客户

         列表。

    C.定义在服务器端主线程为接收线程传递的数据结构ARG。

    struct ARG

    {

    int locate;

    int fifoFd;

    };

    说明:

    locate为与之通信的客户端在在线客户列表中的位置;

    fifoFd为以只写方式打开的管道标识符;

    D.客户端中的全局变量

    pthread_t tid1;       //接收线程的标识符  

    char g_name[NAME_LEN];//客户端用户的名称

    int  g_locate;        //客户端在在线客户列表中的位置

    int  g_total;  //在线客户的总数


    2、流程设计  

    A. 服务器端:

      

    B.客户端:

    三、编码实现

       Public.h

    #ifndef PUBLIC_H_

    #define PUBLIC_H_

    #include"stdio.h"

    #include"stdlib.h"

    #include"string.h"

    #include"sys/socket.h"

    #include"sys/types.h"

    #include"arpa/inet.h"

    #include"netinet/in.h"

    #include"unistd.h"

    #include"pthread.h"

    #define  MAX_CLIENT 3

    #define  NAME_LEN   20

    #define  MSG_LEN    100

    #define  PORT       12345

    #define LOGIN   1

    #define EXIT    2

    #define PUBLIC  3

    #define PRIVATE 4

    #define OK      5

    #define ERROR   -6

    typedef struct ClientList

    {

    char name[NAME_LEN];

    int socketFd;

    }CLIENTLIST;

    typedef struct Message

    {

    char fromUser[NAME_LEN];

        int  fromUserLocate;

    int  type;

    int  sendUserLocate;

    char message[MSG_LEN];

    CLIENTLIST clientList[MAX_CLIENT];

    }MESSAGE;

    CLIENTLIST  clientList[MAX_CLIENT];

    #endif

         

    Server.c

    #include"public.h"

    #include"sys/stat.h"

    #include"fcntl.h"

    #define ADD  7

    #define DEL  8

    #define FIFO  "FIFO"

    struct ARG

    {

    int locate;

    int fifoFd;

    };

    int SearchLocate()

    {

    int i;

    for(i=0;i<MAX_CLIENT;i++)

    {

    if(clientList[i].socketFd==0)break;

    }

    if(i<MAX_CLIENT) return i; else  return -1;

    }

    void TransmitMsg(int cmd,int locate,MESSAGE msg)

    {

        memcpy(&msg.clientList,&clientList,sizeof(clientList));

    if(cmd==PRIVATE)

    {

            write(clientList[msg.sendUserLocate].socketFd,&msg,

    sizeof(msg));

      printf("e[31m#PRIVATE >  From:%-5s  To:  %-5s  

    Msg:%se[0m ",clientList[locate].name,clientList[msg.se ndUserLocate].name,msg.message);

              

    }

    else 

    {

           int i;

       for (i=0;i<MAX_CLIENT;i++)

       {

             if(clientList[i].socketFd!=0 && i!=locate)

         {

                write(clientList[i].socketFd,&msg,sizeof(msg));

        printf("e[32m#PUBLIC  >  From:%-5s  To:  %-5s  

               Msg:%se[0m ",clientList[locate].name,

                clientList[i].name,msg.message);

        } 

     }

      if(cmd==LOGIN)

      {  

              write(clientList[locate].socketFd,&msg,sizeof(msg));

      }

       }

    }

    void UpdateList(int cmd , char *name,int locate)

    {

    if(cmd==ADD)

    {

            strcpy(clientList[locate].name,name);

         printf("e[33m*ADD USER> NAME:%-5s  

    e[0m ",clientList[locate].name);

    }

    else if(cmd==DEL)

    {

         printf("e[33m*DEl USER> NAME:%-5s e[0m ",clientList[locate].name);

        clientList[locate].socketFd=0;

    bzero(clientList[locate].name,NAME_LEN);

    }

    }

    void *RecvMsg(void *arg_t)

    {

         struct ARG arg=*(struct ARG *)arg_t;

     MESSAGE msg;

    while(1)

    {

            int flag;

            bzero(&msg,sizeof(msg));  msg.type=ERROR;

    read(clientList[arg.locate].socketFd,&msg,sizeof(msg));

    msg.fromUserLocate=arg.locate;

       if(msg.type==EXIT||msg.type==ERROR)

       {

       if(msg.type==ERROR)

       {

        strcpy(msg.message,"breakdown");

        printf("e[33m*CLIENT:%s HAD BREAKDOWN

    e[0m ",clientList[msg.fromUserLocate].name);

    msg.type=EXIT;

       }

      if(-1==(flag=write(arg.fifoFd,&msg,sizeof(msg))))

      {

     perror("write fifo error");

     exit(1);

       }

    break;

       }

       if(-1==(flag=write(arg.fifoFd,&msg,sizeof(msg))))

       {

       perror("write fifo error");

       exit(1);

       }

    }

    return NULL;

    }

    void *SendMsg(void *fd)

    {

    int fifoFd;

    if(-1==(fifoFd=open(FIFO,O_RDONLY)))

    {

    perror("open fifo error");

    exit(1);

    }

    int flag;

    MESSAGE msg;

      while(1)

      {

    if(-1==(flag=read(fifoFd,&msg,sizeof(msg))))

    {

    perror("read fifo error");

    exit(2);

    }

        int exit_fd;

    switch(msg.type)

    case LOGIN:

                UpdateList(ADD,msg.fromUser,msg.fromUserLocate);

                TransmitMsg(LOGIN,msg.fromUserLocate,msg);

    break;

    case PUBLIC:

                TransmitMsg(PUBLIC,msg.fromUserLocate,msg);

    break;

    case PRIVATE:

                TransmitMsg(PRIVATE,msg.fromUserLocate,msg);

    break;

    case EXIT:

    exit_fd=clientList[msg.fromUserLocate].socketFd;

                UpdateList(DEL,msg.fromUser,msg.fromUserLocate);

                TransmitMsg(EXIT,msg.fromUserLocate,msg);

    close(exit_fd);

    break;

            default:

    printf("bad data %d   ",msg.type);

    break;

    }

      }

      return NULL;

    }

    int main()

    {

    printf(" service is start..... ");

    pthread_t tid1,tid2;

    int fd,clientfd,wr_fifo;

    socklen_t  sock_len;

    sock_len=sizeof(struct sockaddr_in);

    mkfifo(FIFO,O_CREAT|O_EXCL);

    pthread_create(&tid1,NULL,SendMsg,NULL);

        struct  sockaddr_in server,client;

    server.sin_port=htons(PORT);

    server.sin_family=AF_INET;

    server.sin_addr.s_addr=INADDR_ANY;

        if(-1== (fd=socket(AF_INET,SOCK_STREAM,0)))

        {

       perror("socket error ");

       exit(1);

        }

    if(-1==bind(fd,(struct sockaddr*)&server,sock_len))

    {

    perror("bind error");

    exit(2);

    }

    if(-1==(listen(fd,MAX_CLIENT+1)))

    {

    perror("listen error");

    exit(3);

    }

    if(-1==(wr_fifo=open(FIFO,O_WRONLY)))

    {

    perror("open fifo error");

    exit(1);

    }

        while(1)

    {

    if(-1==(clientfd=(accept(fd,(struct 

    sockaddr*)&client,&sock_len))))

    {

    perror("accept error");

    exit(4);

    }

        int locate=-1;

    MESSAGE msg;

    if(-1==(locate=SearchLocate()))

    {

    printf("e[33m*RECEIVE A APPLY BUT CANNOT ALLOW 

    CONNECTe[0m  ");

    msg.type=EXIT;

    write(clientfd,&msg,sizeof(msg));

    }

    else

    {

            struct ARG arg;

    arg.fifoFd=wr_fifo;

    arg.locate=locate;

    msg.type=OK;            

    memcpy(&msg.clientList,&clientList,sizeof(clientList));

    msg.fromUserLocate=locate;

    write(clientfd,&msg,sizeof(msg));

    clientList[locate].socketFd=clientfd;

    pthread_create(&tid1,NULL,RecvMsg,(void *)&arg);

    }

    }

        pthread_join(tid1,NULL);

        pthread_join(tid2,NULL);

        unlink("FIFO");

    return 0;

    }

    Client.c

    #include"public.h"

    pthread_t tid1;

    char g_name[NAME_LEN];

    int  g_locate;

    int  g_total;

    void flush(){ char c; do{c=getc(stdin);}while(c!=' '&&c!=EOF);};

    int CheckExist()

    {

    int i;

    for(i=0;i<MAX_CLIENT;i++)

    {

    if(!strcmp(g_name,clientList[i].name))

    break;

    }

    if(i<MAX_CLIENT)

    {

    printf("this name: %s is already exist!! ",g_name);

    return 1;

    }

    else

    return 0;

    }

    void  ShowList()

    {

    int i;

    g_total=0;

                     printf("  _____________________________  ");

                     printf(" |         CLIENT LIST         | ");

                     printf(" |_____________________________| ");

         printf(" |e[4m  sort   |      name      e[24m|  ");

            

      for(i=0;i<MAX_CLIENT;i++)

      {

         if(clientList[i].socketFd!=0)

         {

           if(i==g_locate)

       {

         printf(" |e[4;31m *%-4d   |  %-10s   

                     e[0m| ",++g_total,clientList[i].name);

       }

       else

       {

             printf(" |e[4m   %-4d  |  %-10s   

                     e[24m| ",++g_total,clientList[i].name);

       }

         }

       }

                     printf(" |e[4m  Total:%-3d     e[24m| ",g_total);

    }

    int MakeTempList(int *tmp)

    {

    int i,n=0;

      for(i=0;i<MAX_CLIENT;i++)

      {

     if(clientList[i].socketFd!=0)

         { tmp[n]=i; n++; }

      }

        ShowList();

    int select;

    printf("please select the user  ");

    if(1!=scanf("%d",&select))

    {

    flush();

    printf("bad select  ");

    return -1;

    }

    if(select<=g_total)    

    {

    if(tmp[select-1]==g_locate)

    {

    printf("e[33m#SYSTEM:YOU CAN NOT SELECT 

    YOURSELFe[0m ");

    return -1;

    }

    else

    return tmp[select-1];

    }

    else

    {

    printf("bad select  ");

    return -1;

    }

    }

    void *RecvMsg(void *fd)

    {

    int sockfd=*(int *)fd;

    MESSAGE msg;

        

    while(1)

    {

    bzero(&msg,sizeof(msg)); msg.type=ERROR;

    read(sockfd,&msg,sizeof(msg));

    if(msg.type==ERROR)

    break;

    switch(msg.type)

    {

             case LOGIN:

     if(msg.fromUserLocate==g_locate)

     printf("e[34m######  > loing succeede[0m ");

     else

     printf("e[33m#LOGIN  > From:%-10s 

                 Msg:%se[0m ",msg.fromUser,msg.message);

     break;

     case EXIT:

     printf("e[33m#EXIT   > From:%-10s 

     Msg:%se[0m ",clientList[msg.fromUserLocate].name,

     msg.message);

     break;

     case PUBLIC:

     printf("e[32m#PUBLIC > From:%-10s 

                 Msg:%se[0m ",msg.fromUser,msg.message);

     break;

     case PRIVATE:

     printf("e[31m#PRIVATE> From:%-10s 

     Msg:%se[0m ",msg.fromUser,msg.message);

     break;

     default:break;

    }

    memcpy(&clientList,&msg.clientList,sizeof(clientList));

    }

    printf("server is breakdown  ");

    exit(1);

    }

    void SendMsg(int fd)

    {

     

    MESSAGE msg;

        msg.type=LOGIN;

    msg.fromUserLocate=g_locate;

    strcpy(msg.fromUser,g_name);

    strcpy(msg.message,g_name);

        write(fd,&msg,sizeof(msg));

    int tmp[MAX_CLIENT];

    int  key;

    while(1)

    {  

            printf(" 1 public  2 private 3 EXIT 4 client list ");

       if(1!= scanf("%d",&key))

       {

       key=0;

           flush();

       }

    bzero(&msg,sizeof(msg));

        strcpy(msg.fromUser,g_name);

            msg.fromUserLocate=g_locate;

    switch(key)

    {

               case 1:

                   msg.type=PUBLIC;

       printf(" public: please input content  ");

                flush();

       fgets(msg.message,sizeof(msg.message),stdin);

       msg.message[strlen(msg.message)-1]='';

                   write(fd,&msg,sizeof(msg));

       break;

       case 2:

       bzero(tmp,sizeof(tmp));

       msg.type=PRIVATE;

       if(-1!=(msg.sendUserLocate=MakeTempList(tmp)))

       { 

     printf(" private: please input content  ");

                 flush();

         fgets(msg.message,sizeof(msg.message),stdin);

         msg.message[strlen(msg.message)-1]='';

                     write(fd,&msg,sizeof(msg));

       }

       break;

       case 3:

       printf("EXIT  ");

                   msg.type=EXIT;

       strcpy(msg.message,"bye-bye");

                   write(fd,&msg,sizeof(msg));

       break;

       case 4:

       ShowList();

       break;

       default:

       printf("bad select   ");

                   msg.type=0;

       break;

    }

        if(msg.type==EXIT)

    {

    break;

    }

    }

       pthread_cancel(tid1);

    }

    int main()

    {

        int fd;

    char ip[20]="127.0.0.1";

    //printf("please input the ip  ");scanf("%s",ip);

    struct sockaddr_in addr;

    addr.sin_port=htons(PORT);

    addr.sin_family=AF_INET;

       addr.sin_addr.s_addr=inet_addr(ip);

       

    if(-1==(fd=socket(AF_INET,SOCK_STREAM,0)))

    {

    perror("socket error");

    exit(1);

    }

       

    if(-1==(connect(fd,(struct sockaddr*)&addr,sizeof(struct

     sockaddr))))

    {

    perror("connect error");

    exit(2);

    }

       MESSAGE msg;

       read(fd,&msg,sizeof(msg));

       if(msg.type==EXIT)

       {

       printf("service refuse connect  ");

       exit(1);

       }

       else

       {

    memcpy(&clientList,&msg.clientList,sizeof(clientList));

        g_locate=msg.fromUserLocate;

        pthread_create(&tid1,NULL,RecvMsg,(void *)&fd);

        do{

             printf("please input your name ");scanf("%s",g_name);

          }while(CheckExist());

       SendMsg(fd);

       pthread_join(tid1,NULL);

       }

    return 0;

    }

    MAkeFile

    tar:server  client

    server:server.c

    gcc -g -Wall -o  $@  $< -lpthread

    client:client.c

    gcc -g -Wall  -o  $@ $< -lpthread

    c:

    rm -rf server client  FIFO



    源代码:http://download.csdn.net/detail/w1143408997/9408145


  • 相关阅读:
    localstorage实现带过期时间的缓存功能
    移动Web深度剖析
    对接口规范的一些思考
    css代码优化
    Web安全:你必须知道的“Cookie安全”
    androidstudio 常用快捷键
    通过oauth 认证 新浪微博 开发过程中遇到的问题
    【问题】R文件报错原因及解决办法 (转)
    为什么 SharedPreferences 可以直接 调用,前面却没有对象
    关于 android 开发中 debug不能顺利进行的各种问题的总结
  • 原文地址:https://www.cnblogs.com/WK-can-do-anything/p/5792227.html
Copyright © 2020-2023  润新知