linux에서 채팅 프로그램 설계
헤더 파일: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;
}
}
}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.