Chat Room (2) Code Analysis Based on Message Queue and multi-thread programming in Linux

Source: Internet
Author: User
Tags format message strtok

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;}}}     

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.