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:%s\e[0m\n",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:%s\e[0m\n",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\n",clientList[locate].name);

}

else if(cmd==DEL)

{

     printf("\e[33m*DEl USER> NAME:%-5s \e[0m\n",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\n",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  \n",msg.type);

break;

}

  }

  return NULL;

}

 

int main()

{

printf("\n\tservice is start.....\n");

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 

CONNECT\e[0m \n");

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!='\n'&&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!!\n",g_name);

return 1;

}

else

return 0;

}

void  ShowList()

{

int i;

g_total=0;

                 printf("\t _____________________________ \n");

                 printf("\t|         CLIENT LIST         |\n");

                 printf("\t|_____________________________|\n");

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

        

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

  {

 

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

     {

       if(i==g_locate)

   {

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

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

   }

   else

   {

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

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

   }

     }

   }

 

                 printf("\t|\e[4m  Total:%-3d     \e[24m|\n",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 \n");

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

{

flush();

printf("bad select \n");

return -1;

}

if(select<=g_total)    

{

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

{

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

YOURSELF\e[0m\n");

return -1;

}

else

return tmp[select-1];

}

else

{

printf("bad select \n");

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 succeed\e[0m\n");

 else

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

             Msg:%s\e[0m\n",msg.fromUser,msg.message);

 break;

 case EXIT:

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

 Msg:%s\e[0m\n",clientList[msg.fromUserLocate].name,

 msg.message);

 break;

 case PUBLIC:

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

             Msg:%s\e[0m\n",msg.fromUser,msg.message);

 break;

 case PRIVATE:

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

 Msg:%s\e[0m\n",msg.fromUser,msg.message);

 break;

 default:break;

}

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

 

}

printf("server is breakdown \n");

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\n");

   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("\npublic: please input content \n");

            flush();

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

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

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

   break;

   case 2:

   bzero(tmp,sizeof(tmp));

   msg.type=PRIVATE;

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

   { 

 printf("\nprivate: please input content \n");

             flush();

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

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

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

   }

   break;

   case 3:

   printf("EXIT \n");

               msg.type=EXIT;

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

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

   break;

   case 4:

   ShowList();

   break;

   default:

   printf("bad select  \n");

               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 \n");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 \n");

   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\n");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


posted on 2016-01-18 11:24  记住我叫王凯  阅读(2745)  评论(0编辑  收藏  举报

导航