linux下的chat程序设计

linux下通过socket实现聊天功能,代码如下:

头文件:Unp1.h

#include        <sys/types.h>        /* basic system data types */
#include        <sys/socket.h>        /* basic socket definitions */
#include        <sys/time.h>        /* timeval{} for select() */
#include        <time.h>           /* timespec{} for pselect() */
#include        <netinet/in.h>        /* sockaddr_in{} and other Internet defns */
#include        <arpa/inet.h>        /* inet(3) functions */
#include        <errno.h>
#include        <fcntl.h>                /* for nonblocking */
#include        <netdb.h>
#include        <signal.h>
#include        <stdio.h>
#include        <stdlib.h>
#include        <string.h>
#include        <sys/stat.h>       /* for S_xxx file mode constants */
#include        <sys/uio.h>                /* for iovec{} and readv/writev */
#include        <unistd.h>
#include        <sys/wait.h>
#include        <sys/un.h>
#define   MAXLINE   4096
#define   LISTENQ   1024

chat.h代码如下:

/*chat.h*/
#ifndef __CHAT_H
#define __CHAT_H

#include "unp1.h"
#define MAXUSERS 3
/* used to write number of n bytes to socket buffer*/
ssize_t writen(int fd,const void * vptr,size_t n);
/*used to read number of n bytes from the socket buffer*/
ssize_t readn(int fd,void *vptr,size_t n);


struct chat_struct{
              int sock_fd;
              char user_id[20];
              struct in_addr user_ipaddr;
              int next_char;
              int data_pos;
              struct client_cmd{
                    int cmd_type;
                    char user_id[20];
              }cmd;
              char buffer[MAXLINE];
              int slot_status;
           }chater[MAXUSERS];
#define SLOT_FREED 0
#define SLOT_OCCUPIED 1
#define TELL_SOMEONE 1
#define CHAT_ALL 2
/*the two types of the user inputed*/
#define CHATER_LOGOUT 1
#define CHATER_ENTER_A_CMD 2
/*define the message notice to the users*/
char message[4][50]={"to many users in the system.\n",
                      "can not find that user.\n'",
                      "input your user_id:\n",
                      "error command\n"};
/*it is used to select a free slot to the user,if there is not ,it will create one */
void get_free_slot(int sock_fd,char *user_name)                      
{
   int j,flags;
   printf("enter get_free_slot.\n");
   for(j=0;j<MAXUSERS;j++)
   {
      /*if the slot is free ,it will use it*/
      if(chater[j].slot_status==SLOT_FREED)
      {
         chater[j].slot_status=SLOT_OCCUPIED;
         /*remmber the socket_fd in the slot*/
         chater[j].sock_fd=sock_fd;
         /*save the username to supply to the tell*/
         strcpy(chater[j].user_id,user_name);
         /*init the pointer whick point to the user_data_buffer*/
         chater[j].next_char=0;
         /*get the identifer of the socket_fd*/
         flags=fcntl(sock_fd,F_GETFL);
         if(flags==-1)
         {
            perror("get socket attributes error.\n");
            exit(1);
         }else{
               flags|=O_NONBLOCK;
               if(fcntl(sock_fd,F_SETFL,flags)==-1)
                  {
                     perror("change socket attributes failed!\n");
                     exit(1);
                  }
               }
           break;
      }
   }
   if(j==MAXUSERS)
   {
      if(writen(sock_fd,message[0],strlen(message[0]))==-1)
      {
          perror("write to cilent failed!\n");
          exit(1);
      }
      close(sock_fd);
   }
}
                      
/*
 free_slot() release the slot to other users
 slot_index:send the chat user to use the slot 
*/                     
void free_slot(int slot_index) 
{
   /*change the status of the slot*/
   chater[slot_index].slot_status=SLOT_FREED;
   /*close the connection*/
   close(chater[slot_index].sock_fd);
}
/*
  find_chater:return the slot_index,if the slot_index is -1,which means the 
  the user is not in this system
*/                     
int find_chater(char *user_name)                     
{
  int ret,i;
  for(i=0;i<MAXUSERS;i++)
    if(strcmp(chater[i].user_id,user_name)==0)
     {
        ret=i;
        break;
     }
  if(i==MAXUSERS)
       ret==-1;
  return ret;   
  
}
/*
  tell_someone: handle the tell ,send message to the user
  
*/               
void tell_someone(int slot_index)                      
{
   int index,n;
   char *data_p;
   /*use the usename to find the slot*/
   index=find_chater(chater[slot_index].cmd.user_id);
   if(index==-1)
   {
      /*if you do not find the user,so you send a message to the user */
      if(writen(chater[slot_index].sock_fd,message[1],strlen(message[1]))==-1)
      {
         perror("write to the client failed!\n");
         exit(1);
      }
   }else{
          data_p=&(chater[slot_index].buffer[chater[slot_index].data_pos]);
          n=strlen(data_p);
          /*send message to the user of who send the tell*/
          if(writen(chater[slot_index].sock_fd,data_p,n)==-1)
            {
               perror("write message to the user who send tell failed!\n");
               exit(1);
            }
        }
}
/*
   chat_all:send the user_message to all the users who login in the system
*/
void chat_all(int slot_index)                    
{
   int i,n;
   char *data_p;
   for(i=0;i<MAXUSERS;i++)
   {
     if(chater[i].slot_status!=SLOT_FREED&&slot_index!=i)
     {
        data_p=&(chater[slot_index].buffer[chater[i].data_pos]);
        n=strlen(data_p);
        if(writen(chater[i].sock_fd,data_p,n)==-1)
        {
          perror("writen  failed!\n");
          exit(1);
        }
     }
   }
}
/*
  handle_cmd:handle the message
*/
void handle_cmd(int slot_index)
{
  char cmd[6];
  char user_id[20],*pos;
  char detail[MAXLINE];
  int ret,i;
  pos=&(chater[slot_index].buffer[0]);
  while(*pos==' '&&pos<&(chater[slot_index].buffer[MAXLINE]))
     pos++;
  if(*pos=='\n')
  {
     ret=writen(chater[slot_index].sock_fd,message[3],strlen(message[3]));
     if(ret<0&&errno!=EWOULDBLOCK)
       free_slot(slot_index);
     return;
  }
  /*read the command name*/
  i=0;
  while(*pos!=' '&&pos<&(chater[slot_index].buffer[MAXLINE]))
    {
      cmd[i]=*pos++;
      i++;
    }
   cmd[i]='\0';
   /*compare it is tell command*/
   if(strcmp("tell",cmd)==0)
   {
     while(*pos!=' '&&pos<&(chater[slot_index].buffer[MAXLINE]))
     pos++;
     if(*pos=='\n')
     {
       ret=writen(chater[slot_index].sock_fd,message[3],strlen(message[3]));
       if(ret<0&&errno!=EWOULDBLOCK)
         free_slot(slot_index);
         return;
     }
    i=0;
    while(*pos!=' '&&pos<&(chater[slot_index].buffer[MAXLINE]))
    {
      user_id[i]=*pos++;
      i++;
    }
    user_id[i]='\0';
    /*to find the real message*/
    while(*pos=' '&&pos<&(chater[slot_index].buffer[MAXLINE]))
      {
       pos++;
    /*if the style is wrong ,so send the wrong message warning*/
      if(*pos=='\n')
      {
        ret=writen(chater[slot_index].sock_fd,message[3],strlen(message[3]));
        if(ret<0&&errno!=EWOULDBLOCK)
           free_slot(slot_index);
       return;
      }
    /*to save the message place*/
    chater[slot_index].data_pos=pos-chater[slot_index].buffer;
    /*save the revalent message in the stuct in client_cmd*/
    strcpy(chater[slot_index].cmd.user_id,user_id);
    chater[slot_index].cmd.cmd_type=TELL_SOMEONE;
    
   }
   /*compare it is chat command or not*/
   if(strcpy("chat",cmd)==0)
   {
     chater[slot_index].cmd.cmd_type=CHAT_ALL;
     chater[slot_index].data_pos=pos-chater[slot_index].buffer;
   }
   /*use the command_handle_function*/
   if(chater[slot_index].cmd.cmd_type==TELL_SOMEONE)
     tell_someone(slot_index);
   if(chater[slot_index].cmd.cmd_type==CHAT_ALL)
     chat_all(slot_index);
  }                      
}                     
/*
  check_chater_status:check the status of the user
  which divide into three status,
  the frist:user send a message,the wait the server handle the message
  the second:user exit the syetem and wait the server clean the slot
  the third:the left 
*/                     
int check_chater_status(int slot_index)                      
{  
   char *ptr;
   int n;
   ptr=&(chater[slot_index].buffer[chater[slot_index].next_char]);
   while((n=read(chater[slot_index].sock_fd,ptr,1))==1)
   {
   /*if the message you read is a '\n',which means the really message is arrived*/
   if(*ptr=='\n')
   {
      /*set the next byte as '\0'*/
      *(ptr+1)='\0';
      /*init the place for the next data will readin */
      chater[slot_index].next_char=0;
      /*return a command*/
      return CHATER_ENTER_A_CMD;
   }
   /*if the client input the data fullfil the buffer,so ignore the next message*/
   if(++chater[slot_index].next_char==MAXLINE)
     --chater[slot_index].next_char;
   else
    ++ptr;
   }
  /*if receive the end of the file,it means the user exit the system now*/
  if(n==0)
    return CHATER_LOGOUT;
  if(n<0&&errno!=EWOULDBLOCK)
    free_slot(slot_index)                   ;
   return 0;
}                      
                      
 /*
 writen:send message to the buffer,then return the size of you send 
 */                     
ssize_t writen(int fd,const void *vptr,size_t n)                      
{
  size_t nleft;
  ssize_t nwritten;
  const char *ptr;
  ptr=vptr;
  nleft=n;
  while(nleft>0)
  {
    if(nwritten=write(fd,ptr,nleft)<=0)
    {
      if(errno==EWOULDBLOCK)
        nwritten=0;
      else
         return -1;
    }
    nleft-=nwritten;
    ptr+=nwritten;
  }
  return n;
}
                      
/*
   readn:use to read data from the socket_buffer 
*/                      
ssize_t readn(int fd,void *vptr,size_t n)                      
{
  size_t nleft;
  ssize_t nread;
  char *ptr;
  ptr=vptr;
  nleft=n;
  while(nleft>0)
  {
     if((nread=read(fd,ptr,nleft))<0)
     {
        if(errno==EWOULDBLOCK)
          nread=0;
        else 
         return -1;
     }else if(nread==0)
            break;
     nleft-=nread;
     ptr+=nread;
     
  }
  return (n-nleft);
}
                      
 static ssize_t  my_common_read(int fd,char *ptr)
{
  static int read_cnt=0;
  static char *read_ptr;
  static char read_buf[MAXLINE];
  if(read_cnt<=0)
  {
    again:
      if((read_cnt=read(fd,read_buf,sizeof(read_buf)))<0)
      {  
         if(errno==EINTR)
           goto again;
           return -1;
      }
      else if(read_cnt==0)
             return 0;
     read_ptr=read_buf;
  }
  read_cnt--;
  *ptr=*read_ptr++;
  return 1;
}  
/*read a line message from the socket_buffer*/                    
ssize_t commonreadline(int fd,void *vptr,size_t maxlen)
{
  int n,rc;
  
  char c,*ptr;
  static times=0;
  ptr=vptr;
  for( n=0;n<maxlen;n++)
  {
     if((rc=my_common_read(fd,&c))==1)
     {
       *ptr++=c;
       if(c=='\n')
       {
         times++;
         if(times==1)
           break;
       }
       else times=0;
     }else 
         if(rc==0)
            {
              if(n==1)
                  return 0;
              else break;
            }
          else  return -1;
  }
  *ptr=0;
  return n;
}
#endif                    
                 

chat.c代码:

#include "unp1.h"
#include "chat.h"
#define SERVER_PORT 9000

int main(int argc,char * argv[])
{
   int listen_fd,conn_fd;
   socklen_t cli_len;
   struct sockaddr_in cli_addr,serv_addr;
   int ret,flags;
   int re_use_addr=1;
   char recv_buf[MAXLINE];
   int i;
   char *ptr;
   for(i=0;i<MAXUSERS;i++)
    {  
       chater[i].slot_status=SLOT_FREED;
       chater[i].sock_fd=-1;
       chater[i].cmd.cmd_type=-1;
    }
   listen_fd=socket(AF_INET,SOCK_STREAM,0);
   if(listen_fd==-1)
   {
     perror("listen socket failed!");
     exit(1);
   }
   bzero(&serv_addr,sizeof(serv_addr));
   serv_addr.sin_family=AF_INET;
   serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
   serv_addr.sin_port=htons(SERVER_PORT);
   setsockopt(listen_fd,SOL_SOCKET,SO_REUSEADDR,(void *)&re_use_addr,sizeof(int));
   ret=bind(listen_fd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
   if(ret<0)
   { 
      perror("bind socket failed!");
      exit(1);
   }
   listen(listen_fd,LISTENQ);
   if((flags=fcntl(listen_fd,F_GETFL,0))<0)
      perror("F_GETFL error");
   flags|=O_NONBLOCK;
   if(fcntl(listen_fd,F_SETFL,flags)<0)
     perror("F_SETFL error");
   while(1)
   {
      cli_len=sizeof(cli_addr);
      conn_fd=accept(listen_fd,(struct sockaddr*)&cli_addr,&cli_len);
      if(conn_fd<0&&errno!=EWOULDBLOCK)
      { 
         perror("accept socket failed!");
         exit(1);
      }else if(conn_fd>0)
             {
                printf("the server create a new connection\n");
                ret=writen(conn_fd,message[2],strlen(message[2]));
                if(ret<0&&errno==EINTR)
                 {
                    perror("write to the client failed!");
                    close(conn_fd);
                    continue;
                 }
              ret=commonreadline(conn_fd,recv_buf,MAXLINE);
              if(ret<0&&errno==EWOULDBLOCK)
                 {
                    printf("read from the client failed!");
                    close(conn_fd);
                    continue;
                 }
              ptr=recv_buf;
              while(*ptr!='\r')
                ptr++;
              *ptr='\0';
              get_free_slot(conn_fd,recv_buf);
             }
        for(i=0;i<MAXUSERS;i++)
          {
             if(chater[i].slot_status==SLOT_OCCUPIED)
             {
               switch(check_chater_status(i))
               {
                  case CHATER_ENTER_A_CMD:
                                           handle_cmd(i);
                                           break;
                  case CHATER_LOGOUT:
                                           free_slot(i);
                                           break;
               }
             }
          }
      }
  }



你可能感兴趣的:(linux下的chat程序设计)