linux에서 채팅 프로그램 설계

14611 단어
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.
", "can not find that user.
'", "input your user_id:
", "error command
"}; /*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.
"); 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.
"); exit(1); }else{ flags|=O_NONBLOCK; if(fcntl(sock_fd,F_SETFL,flags)==-1) { perror("change socket attributes failed!
"); exit(1); } } break; } } if(j==MAXUSERS) { if(writen(sock_fd,message[0],strlen(message[0]))==-1) { perror("write to cilent failed!
"); 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!
"); 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!
"); 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!
"); 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=='
') { 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=='
') { 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=='
') { 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 '
',which means the really message is arrived*/ if(*ptr=='
') { /*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=='
') { 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
"); 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; } } } } }

좋은 웹페이지 즐겨찾기