Paste the code first, and then explain it slowly.
@ Makefile
OBJS := server clientall: $(OBJS)server: msg_svr.c msg.h gcc -o $@ $^ -D_DEBUGclient: msg_client.c msg.hgcc -o $@ $^ -lpthreadclean:$(RM) $(OBJS)
@ Msg. h
#include <stdlib.h>#include <string.h>#include <stdio.h>#include <fcntl.h>#include <signal.h>#include <errno.h>#include <time.h>#include <sys/msg.h>#define MSG_FILE "/tmp/msg_server" #define BUFFER 255 #define PERM S_IRUSR | S_IWUSR #define OK1 #define ERR0// msg type#define TYPE_SERVER1000#define TYPE_SERVER_STR"1000"// msg target string#define SERVER_STR"SERVER"#define TO_ALL_STR"ALL"// send cmd// L, I, O is send to server#define CMD_LIST'L'#define CMD_LOGIN'I'#define CMD_LOGOUT'O'#define CMD_TOALL 'A'// C, F send to others#define CMD_CHAT'C'#define CMD_SEND_FILE'F'// CMD:FROM:TIME:DATA #defineDATA_LEN4#defineOFT_CMD0#defineOFT_FRM1#defineOFT_TIM2#defineOFT_DAT3#defineDATA_TOK":"// USR_ID:USR_NAME:TIME#defineUSER_DATA_LEN3#defineOFT_USR_ID0#defineOFT_USR_NM1#defineOFT_LOGIN_TM2#defineUSER_DATA_TOK"#"// id admin#define START_ID1//-------------------------------------+// List operationsstruct list_head {struct list_head *next;};// init a new list named name#define LIST_INIT(name)\struct list_head name = {NULL}static inline int list_add(struct list_head * head, struct list_head* new){new->next = head->next;head->next = new;}static inline int list_delete(struct list_head * head, struct list_head* target){while(head){if(head->next == target){head->next = target->next;return 0;}head = head->next;}return -1;}//-------------------------------------+// online statusenum status{ online, offline, invisible };// available id int available_id = START_ID;// user struct to save user informationsstruct user{struct list_head list;int id;char name[32];enum status status;;long login_time;};// message structstruct message{ long mtype;char buffer[BUFFER+1]; }msg_snd, msg_rcv; int msgid = 0;// send a format message to client// CMD:FROM:TIME:DATA int send_msg(long type, int cmd, int from_id, char * data){sprintf(msg_snd.buffer, "%c:%d:%d:%s", cmd, from_id, time(NULL), data);msg_snd.mtype = type;if(msgsnd(msgid, &msg_snd, strlen(msg_snd.buffer)+1, 0) < 0)return ERR;elsereturn OK;}inline char *time2str(long time, char* buf){struct tm *t = localtime(&time);strftime(buf, 32, "%Y-%m-%d-%H:%M:%S", t);return buf;}int init_msg_queue(){key_t key;if((key = ftok(MSG_FILE, 'a')) == -1){perror("ftok");exit(1);} printf("Key:%d\n", key);if((msgid = msgget(key, PERM | IPC_CREAT)) == -1){ perror("msgget");exit(1);} printf("msgid = %d\n", msgid);return msgid;} int process_msg(char* buffer);
@ Msg_svr.c
/* msg_svr.c */ #include "msg.h" LIST_INIT(msg_list_head); int main() { msgid = init_msg_queue();while(1) {if(msgrcv(msgid, &msg_rcv, sizeof(struct message), TYPE_SERVER, 0) == -1)perror("msgrcv");elseprintf("Get: %s\n", msg_rcv.buffer);// process messageprocess_msg(msg_rcv.buffer);} exit(0); }// process message received from message queue// message format:// CMD:TARGET:FROM:TIME:DATAint process_msg(char* buffer){char * data[DATA_LEN];char * str, *subtoken;int i;memset(data, NULL, sizeof(data));for(str = buffer, i = 0; ; str = NULL, i++){subtoken = strtok(str, DATA_TOK);if(subtoken == NULL)break;data[i] = subtoken;#ifdef _DEBUGprintf("> data[%d] = %s\n", i, subtoken);#endif}// data format errorif(i != DATA_LEN)return ERR;char info[256];char buf[256];struct user* u ;struct list_head* p;// send to server cmdswitch(data[OFT_CMD][0]){case CMD_LIST:bzero(buf, sizeof(buf));p = (&msg_list_head)->next;while(p){u= (struct user*)p;sprintf(info, "%d#%s#%ld#", u->id, u->name, u->login_time);#ifdef _DEUBGprintf("u->name = %s\n", u->name);#endifstrcat(buf, info);p = p->next;}if(p != msg_list_head.next){// delete the end '#'buf[strlen(buf) - 1] = 0;}send_msg(atol(data[OFT_FRM]), CMD_LIST, TYPE_SERVER, buf);break;case CMD_LOGIN:u = (struct user *)malloc(sizeof(struct user));if(NULL == u){perror("malloc");return ERR;}// add to listlist_add(&msg_list_head, &(u->list));u->id = available_id++;strcpy(u->name, data[OFT_FRM]);u->status = online;u->login_time = atol(data[OFT_TIM]);// login ok echo msgmsg_snd.mtype = atol(data[OFT_DAT]); sprintf(msg_snd.buffer, "%d", u->id);msgsnd(msgid, &msg_snd, strlen(buf)+1, 0); break;case CMD_LOGOUT:p = (&msg_list_head)->next;while(p){u= (struct user*)p;// find the user who request logoutif(u->id == atoi(data[OFT_FRM])){if(send_msg(u->id, CMD_LOGOUT, TYPE_SERVER, "Logout OK!") == OK){list_delete(&msg_list_head, p);free(p);}else{return ERR;}break;}p = p->next;}break;case CMD_TOALL:// send to all online clientp = (&msg_list_head)->next;while(p){u= (struct user*)p;send_msg(u->id, CMD_CHAT, data[OFT_FRM], data[OFT_DAT]);p = p->next;}break;default:return ERR;}return OK;}
@ Msg_client.c
/* msg_client.c */ #include "msg.h" int userid = 0;char name[32] = "";void print_menu(void){printf("\t+----------------------------------+\n");printf("\t+ Chat Room V1.0 2013.01.08 +\n");printf("\t+----------------------------------+\n");printf("\t+ User Commands as follows: +\n");printf("\t+ +\n");printf("\t+ l: list all online user +\n");printf("\t+ i: Login +\n");printf("\t+ o: logOut +\n");printf("\t+ c: Chat with other online user +\n");printf("\t+ a: Chat with all online user +\n");printf("\t+ f: transfer a File to others +\n");printf("\t+ h: Help +\n");printf("\t+----------------------------------+\n");}int get_choice(){printf("%s# ", name);int answer = getchar();// eat <Enter>while(getchar() != '\n');// eat <Enter>//putchar(answer);return answer;}void func(int sig){printf("\n%s# ", name);fflush(stdout);}int send_to(int target, int cmd, char *data){return send_msg(target, cmd, userid, data);}int send_server(int cmd, char *data){return send_msg(TYPE_SERVER, cmd, userid, data);}int chat(){if(strlen(name) == 0){printf("You are not login!\n");return ERR;}char id[32];char data[256];char buf[256];printf("To: [USR_ID] ");fflush(stdout);if(fgets(id, sizeof(id), stdin) == NULL){perror("fgets");return ERR;}sprintf(data, " %s > ", name);id[strlen(id) - 1] = 0;printf(">> ");fflush(stdout);if(fgets(buf, sizeof(buf), stdin) == NULL){perror("fgets");return ERR;}strcat(data, buf);data[strlen(data) - 1] = 0;send_to(atoi(id), CMD_CHAT, data);}int chat_all(){if(strlen(name) == 0){printf("You are not login!\n");return ERR;}char data[256];char buf[256];sprintf(data, " %s To all > ", name);printf("To all >> ");fflush(stdout);if(fgets(buf, sizeof(buf), stdin) == NULL){perror("fgets");return ERR;}strcat(data, buf);data[strlen(data) - 1] = 0;send_to(TYPE_SERVER, CMD_TOALL, data);}int login(){printf("username: \n");if(fgets(name, sizeof(name), stdin) == NULL){perror("fgets");return ERR;}name[strlen(name) - 1] = 0;int rand_type = random();time_t t;time(&t);sprintf(msg_snd.buffer, "%c:%s:%ld:%d", CMD_LOGIN, name, t, rand_type);#ifdef _DEBUGprintf("%s\n", msg_snd.buffer);#endif// get a random type to login servermsg_snd.mtype = TYPE_SERVER;if(msgsnd(msgid, &msg_snd, strlen(msg_snd.buffer)+1, 0) < 0){perror("msgsnd");return ERR;}// wait server responseif(msgrcv(msgid, &msg_rcv, sizeof(msg_rcv), rand_type, 0) < 0){return ERR;} else{userid = atol(msg_rcv.buffer);printf("Login OK id = %d\n", userid);return OK;}}int logout(){if(strlen(name) == 0){return ERR;}send_server(CMD_LOGOUT, "Logout");// wait server responseif(msgrcv(msgid, &msg_rcv, sizeof(msg_rcv), userid, 0) < 0){return ERR;}else{userid = 0;printf("Logout OK\n");return OK;}}void format_user_list(char * buffer){char * data[USER_DATA_LEN];char * str, *subtoken;char time_buf[24];int i, n;memset(data, NULL, sizeof(data));printf("----------------------------------\n");printf(" _ID_ USR_NAME Login_Time \n");printf("----------------------------------\n");for(str = buffer, i = 0, n = 1; ; str = NULL, i++){subtoken = strtok(str, USER_DATA_TOK);if(subtoken == NULL)break;data[i] = subtoken;#ifdef _DEBUGprintf("> data[%d] = %s\n", i, subtoken);#endifif(i != 0 && i % 2 == 0){printf(" %4s %8s %s\n", data[OFT_USR_ID], data[OFT_USR_NM], time2str(atol(data[OFT_LOGIN_TM]), time_buf));n++;i = -1;}}}void * receiver_looper(void * p){if(userid == 0)return NULL;char * data[DATA_LEN];char * str, *subtoken;int i;while(1){if(msgrcv(msgid, &msg_rcv, sizeof(msg_rcv), userid, 0) < 0){perror("msgrcv");continue;}else{#ifdef _DEBUGprintf("%s received: %s\n", __func__, msg_rcv.buffer);#endifmemset(data, NULL, sizeof(data));for(str = msg_rcv.buffer, i = 0; ; str = NULL, i++){subtoken = strtok(str, DATA_TOK);if(subtoken == NULL)break;data[i] = subtoken;#ifdef _DEBUGprintf("> data[%d] = %s\n", i, subtoken);#endif}// process received data// data format errorif(i != DATA_LEN)continue;switch(data[OFT_CMD][0]){case CMD_LIST:if(strcmp(data[OFT_FRM], TYPE_SERVER_STR)){continue;}format_user_list(data[OFT_DAT]);break;case CMD_LOGOUT:if(strcmp(data[OFT_FRM], TYPE_SERVER_STR)){continue;}printf("> %s ", data[OFT_DAT]);printf("%s\n", time2str(atol(data[OFT_TIM]), data[OFT_DAT]));exit(0);case CMD_CHAT:// print chat contentprintf("\n%s \n\t\t", data[OFT_DAT]);printf("%s\n", time2str(atol(data[OFT_TIM]), data[OFT_DAT]));printf("\n%s# ", name);fflush(stdout);break;case CMD_SEND_FILE:break;}}}}int main(int argc, char **argv) { signal(SIGINT, func);//signal(SIGQUIT, func);msgid = init_msg_queue();pthread_t thread;// print help menuprint_menu();while(1){switch(get_choice()){case 'i':if(login() == OK) while(pthread_create(&thread, NULL, receiver_looper, NULL) < 0);break;case 'l':send_server(CMD_LIST, "List");sleep(1);break;case 'o':if(logout() == OK){pthread_join(thread, NULL);return 0;}else{printf("Not login quit\n");return 0;}break;case 'c':chat();break;case 'a':chat_all();break;break;case 'h':print_menu();break;case 'f':break;}}}