基于Linux的消息队列及多线程编程实现的聊天室(二)代码分析

转载 2015年11月17日 21:50:13

http://blog.csdn.net/mr_raptor/article/details/8484822

先将代码贴出来,然后慢慢再解释.

@Makefile

  1. OBJS := server client  
  2. all: $(OBJS)  
  3.   
  4. server: msg_svr.c msg.h   
  5.     gcc -o $@ $^ -D_DEBUG  
  6.   
  7. client: msg_client.c msg.h  
  8.     gcc -o $@ $^ -lpthread  
  9.   
  10. clean:  
  11.     $(RM) $(OBJS)  

@msg.h

  1. #include <stdlib.h>  
  2. #include <string.h>  
  3. #include <stdio.h>  
  4. #include <fcntl.h>  
  5. #include <signal.h>  
  6. #include <errno.h>  
  7. #include <time.h>  
  8. #include <sys/msg.h>  
  9.   
  10. #define   MSG_FILE "/tmp/msg_server"      
  11. #define   BUFFER 255      
  12. #define   PERM S_IRUSR | S_IWUSR      
  13.   
  14. #define     OK          1   
  15. #define     ERR         0  
  16.   
  17. // msg type  
  18. #define   TYPE_SERVER       1000  
  19. #define   TYPE_SERVER_STR   "1000"  
  20.   
  21. // msg target string  
  22. #define   SERVER_STR        "SERVER"  
  23. #define   TO_ALL_STR        "ALL"  
  24.   
  25. // send cmd  
  26. // L, I, O is send to server  
  27. #define     CMD_LIST        'L'  
  28. #define     CMD_LOGIN       'I'  
  29. #define     CMD_LOGOUT      'O'  
  30. #define     CMD_TOALL       'A'  
  31.   
  32. // C, F send to others  
  33. #define     CMD_CHAT        'C'  
  34. #define     CMD_SEND_FILE   'F'  
  35.   
  36. // CMD:FROM:TIME:DATA   
  37. #define     DATA_LEN    4  
  38. #define     OFT_CMD     0  
  39. #define     OFT_FRM     1  
  40. #define     OFT_TIM     2  
  41. #define     OFT_DAT     3  
  42. #define     DATA_TOK    ":"  
  43.   
  44. // USR_ID:USR_NAME:TIME  
  45. #define     USER_DATA_LEN   3  
  46. #define     OFT_USR_ID      0  
  47. #define     OFT_USR_NM      1  
  48. #define     OFT_LOGIN_TM    2  
  49. #define     USER_DATA_TOK   "#"  
  50.   
  51. // id admin  
  52. #define     START_ID    1  
  53.   
  54. //-------------------------------------+  
  55. // List operations  
  56. struct list_head {  
  57.     struct list_head *next;  
  58. };  
  59.   
  60. // init a new list named name  
  61. #define LIST_INIT(name) \  
  62.     struct list_head name = {NULL}  
  63.   
  64. static inline int list_add(struct list_head * head, struct list_head* new){  
  65.     new->next = head->next;  
  66.     head->next = new;  
  67. }  
  68.   
  69. static inline int list_delete(struct list_head * head, struct list_head* target){  
  70.     while(head){  
  71.         if(head->next == target){  
  72.             head->next = target->next;  
  73.             return 0;  
  74.         }  
  75.         head = head->next;  
  76.     }  
  77.     return -1;  
  78. }  
  79. //-------------------------------------+  
  80.   
  81. // online status  
  82. enum status{ online, offline, invisible };  
  83.   
  84. // available id   
  85. int available_id = START_ID;  
  86.   
  87. // user struct to save user informations  
  88. struct user{  
  89.     struct list_head list;  
  90.     int id;  
  91.     char name[32];  
  92.     enum status status;;  
  93.     long login_time;  
  94. };  
  95.   
  96. // message struct  
  97. struct message  
  98. {      
  99.     long mtype;  
  100.     char buffer[BUFFER+1];      
  101. }msg_snd, msg_rcv;      
  102.   
  103. int msgid = 0;  
  104.   
  105. // send a format message to client  
  106. // CMD:FROM:TIME:DATA   
  107. int send_msg(long type, int cmd, int from_id, char * data){  
  108.     sprintf(msg_snd.buffer, "%c:%d:%d:%s", cmd, from_id, time(NULL), data);  
  109.     msg_snd.mtype = type;  
  110.     if(msgsnd(msgid, &msg_snd, strlen(msg_snd.buffer)+1, 0) < 0)  
  111.         return ERR;  
  112.     else  
  113.         return OK;  
  114. }  
  115.   
  116. inline char *time2str(long time, char* buf){  
  117.     struct tm *t = localtime(&time);  
  118.     strftime(buf, 32, "%Y-%m-%d-%H:%M:%S", t);  
  119.     return buf;  
  120. }  
  121.   
  122. int init_msg_queue(){  
  123.     key_t key;  
  124.     if((key = ftok(MSG_FILE, 'a')) == -1){  
  125.         perror("ftok");  
  126.         exit(1);  
  127.     }   
  128.   
  129.     printf("Key:%d\n", key);  
  130.     if((msgid = msgget(key, PERM | IPC_CREAT)) == -1)  
  131.     {     
  132.         perror("msgget");  
  133.         exit(1);  
  134.     }         
  135.     printf("msgid = %d\n", msgid);  
  136.     return msgid;  
  137. }         
  138.   
  139. int process_msg(char* buffer);    



@msg_svr.c

  1. /* msg_svr.c */    
  2.   
  3. #include "msg.h"     
  4.   
  5. LIST_INIT(msg_list_head);   
  6.   
  7. int main()      
  8. {      
  9.     msgid = init_msg_queue();  
  10.   
  11.     while(1)     
  12.     {  
  13.         if(msgrcv(msgid, &msg_rcv, sizeof(struct message), TYPE_SERVER, 0) == -1)  
  14.             perror("msgrcv");  
  15.         else  
  16.             printf("Get: %s\n", msg_rcv.buffer);  
  17.   
  18.         // process message  
  19.         process_msg(msg_rcv.buffer);  
  20.     }      
  21.     exit(0);      
  22. }  
  23.   
  24. // process message received from message queue  
  25. // message format:  
  26. // CMD:TARGET:FROM:TIME:DATA  
  27. int process_msg(char* buffer){  
  28.     char * data[DATA_LEN];  
  29.     char * str, *subtoken;  
  30.     int i;  
  31.     memset(data, NULL, sizeof(data));  
  32.     for(str = buffer, i = 0; ; str = NULL, i++){  
  33.         subtoken = strtok(str, DATA_TOK);  
  34.         if(subtoken == NULL)  
  35.             break;  
  36.         data[i] = subtoken;  
  37. #ifdef _DEBUG  
  38.         printf("> data[%d] = %s\n", i, subtoken);  
  39. #endif  
  40.     }  
  41.     // data format error  
  42.     if(i != DATA_LEN)  
  43.         return ERR;  
  44.   
  45.     char info[256];  
  46.     char buf[256];  
  47.     struct user* u ;  
  48.     struct list_head* p;  
  49.   
  50.     // send to server cmd  
  51.     switch(data[OFT_CMD][0]){  
  52.     case CMD_LIST:  
  53.         bzero(buf, sizeof(buf));  
  54.         p = (&msg_list_head)->next;  
  55.         while(p){  
  56.             u= (struct user*)p;  
  57.             sprintf(info, "%d#%s#%ld#", u->id, u->name, u->login_time);  
  58. #ifdef _DEUBG  
  59.             printf("u->name = %s\n", u->name);  
  60. #endif  
  61.             strcat(buf, info);  
  62.             p = p->next;  
  63.         }  
  64.         if(p != msg_list_head.next){  
  65.             // delete the end '#'  
  66.             buf[strlen(buf) - 1] = 0;  
  67.         }  
  68.         send_msg(atol(data[OFT_FRM]), CMD_LIST, TYPE_SERVER, buf);  
  69.         break;  
  70.   
  71.     case CMD_LOGIN:  
  72.         u = (struct user *)malloc(sizeof(struct user));  
  73.         if(NULL == u){  
  74.             perror("malloc");  
  75.             return ERR;  
  76.         }  
  77.         // add to list  
  78.         list_add(&msg_list_head, &(u->list));  
  79.         u->id = available_id++;  
  80.         strcpy(u->name, data[OFT_FRM]);  
  81.         u->status = online;  
  82.         u->login_time = atol(data[OFT_TIM]);  
  83.   
  84.         // login ok echo msg  
  85.         msg_snd.mtype = atol(data[OFT_DAT]);                  
  86.         sprintf(msg_snd.buffer, "%d", u->id);  
  87.         msgsnd(msgid, &msg_snd, strlen(buf)+1, 0);    
  88.         break;  
  89.   
  90.     case CMD_LOGOUT:  
  91.         p = (&msg_list_head)->next;  
  92.         while(p){  
  93.             u= (struct user*)p;  
  94.             // find the user who request logout  
  95.             if(u->id == atoi(data[OFT_FRM])){  
  96.                 if(send_msg(u->id, CMD_LOGOUT, TYPE_SERVER, "Logout OK!") == OK){  
  97.                     list_delete(&msg_list_head, p);  
  98.                     free(p);  
  99.                 }else{  
  100.                     return ERR;  
  101.                 }  
  102.                 break;  
  103.             }  
  104.             p = p->next;  
  105.         }  
  106.         break;  
  107.   
  108.     case CMD_TOALL:  
  109.         // send to all online client  
  110.         p = (&msg_list_head)->next;  
  111.         while(p){  
  112.             u= (struct user*)p;  
  113.             send_msg(u->id, CMD_CHAT, data[OFT_FRM], data[OFT_DAT]);  
  114.             p = p->next;  
  115.         }  
  116.         break;  
  117.     default:  
  118.         return ERR;  
  119.     }  
  120.     return OK;  
  121. }  

@msg_client.c

  1. /* msg_client.c */    
  2. #include "msg.h"     
  3.   
  4. int userid = 0;  
  5.   
  6. char name[32] = "";  
  7.   
  8. void print_menu(void){  
  9.     printf("\t+----------------------------------+\n");  
  10.     printf("\t+    Chat Room V1.0 2013.01.08     +\n");  
  11.     printf("\t+----------------------------------+\n");  
  12.     printf("\t+ User Commands as follows:        +\n");  
  13.     printf("\t+                                  +\n");  
  14.     printf("\t+ l: list all online user          +\n");  
  15.     printf("\t+ i: Login                         +\n");  
  16.     printf("\t+ o: logOut                        +\n");  
  17.     printf("\t+ c: Chat with other online user   +\n");  
  18.     printf("\t+ a: Chat with all online user     +\n");  
  19.     printf("\t+ f: transfer a File to others     +\n");  
  20.     printf("\t+ h: Help                          +\n");  
  21.     printf("\t+----------------------------------+\n");  
  22. }  
  23.   
  24. int get_choice(){  
  25.     printf("%s# ", name);  
  26.     int answer = getchar(); // eat <Enter>  
  27.     while(getchar() != '\n');   // eat <Enter>  
  28.     //putchar(answer);  
  29.     return answer;  
  30. }  
  31.   
  32. void func(int sig){  
  33.     printf("\n%s# ", name);  
  34.     fflush(stdout);  
  35. }  
  36.   
  37. int send_to(int target, int cmd, char *data){  
  38.     return send_msg(target, cmd, userid, data);  
  39. }  
  40.   
  41. int send_server(int cmd, char *data){  
  42.     return send_msg(TYPE_SERVER, cmd, userid, data);  
  43. }  
  44.   
  45. int chat(){  
  46.     if(strlen(name) == 0){  
  47.         printf("You are not login!\n");  
  48.         return ERR;  
  49.     }  
  50.   
  51.     char id[32];  
  52.     char data[256];  
  53.     char buf[256];  
  54.     printf("To: [USR_ID] ");  
  55.     fflush(stdout);  
  56.     if(fgets(id, sizeof(id), stdin) == NULL){  
  57.         perror("fgets");  
  58.         return ERR;  
  59.     }  
  60.     sprintf(data, " %s > ", name);  
  61.     id[strlen(id) - 1] = 0;  
  62.   
  63.     printf(">> ");  
  64.     fflush(stdout);  
  65.     if(fgets(buf, sizeof(buf), stdin) == NULL){  
  66.         perror("fgets");  
  67.         return ERR;  
  68.     }  
  69.     strcat(data, buf);  
  70.     data[strlen(data) - 1] = 0;  
  71.     send_to(atoi(id), CMD_CHAT, data);  
  72. }  
  73.   
  74. int chat_all(){  
  75.     if(strlen(name) == 0){  
  76.         printf("You are not login!\n");  
  77.         return ERR;  
  78.     }  
  79.   
  80.     char data[256];  
  81.     char buf[256];  
  82.     sprintf(data, " %s To all > ", name);  
  83.   
  84.     printf("To all >> ");  
  85.     fflush(stdout);  
  86.     if(fgets(buf, sizeof(buf), stdin) == NULL){  
  87.         perror("fgets");  
  88.         return ERR;  
  89.     }  
  90.     strcat(data, buf);  
  91.     data[strlen(data) - 1] = 0;  
  92.     send_to(TYPE_SERVER, CMD_TOALL, data);  
  93. }  
  94.   
  95. int login(){  
  96.     printf("username: \n");  
  97.     if(fgets(name, sizeof(name), stdin) == NULL){  
  98.         perror("fgets");  
  99.         return ERR;  
  100.     }  
  101.     name[strlen(name) - 1] = 0;  
  102.     int rand_type = random();  
  103.     time_t t;  
  104.     time(&t);  
  105.     sprintf(msg_snd.buffer, "%c:%s:%ld:%d", CMD_LOGIN, name, t, rand_type);  
  106. #ifdef _DEBUG  
  107.     printf("%s\n", msg_snd.buffer);  
  108. #endif  
  109.     // get a random type to login server  
  110.     msg_snd.mtype = TYPE_SERVER;  
  111.     if(msgsnd(msgid, &msg_snd, strlen(msg_snd.buffer)+1, 0) < 0){  
  112.         perror("msgsnd");  
  113.         return ERR;  
  114.     }  
  115.   
  116.     // wait server response  
  117.     if(msgrcv(msgid, &msg_rcv, sizeof(msg_rcv), rand_type, 0) < 0){  
  118.         return ERR;  
  119.     } else{  
  120.         userid = atol(msg_rcv.buffer);  
  121.         printf("Login OK id = %d\n", userid);  
  122.         return OK;  
  123.     }  
  124. }  
  125.   
  126. int logout(){  
  127.     if(strlen(name) == 0){  
  128.         return ERR;  
  129.     }  
  130.     send_server(CMD_LOGOUT, "Logout");  
  131.     // wait server response  
  132.     if(msgrcv(msgid, &msg_rcv, sizeof(msg_rcv), userid, 0) < 0){  
  133.         return ERR;  
  134.     }else{  
  135.         userid = 0;  
  136.         printf("Logout OK\n");  
  137.         return OK;  
  138.     }  
  139. }  
  140.   
  141. void format_user_list(char * buffer){  
  142.     char * data[USER_DATA_LEN];  
  143.     char * str, *subtoken;  
  144.     char time_buf[24];  
  145.     int i, n;  
  146.     memset(data, NULL, sizeof(data));  
  147.     printf("----------------------------------\n");   
  148.     printf(" _ID_  USR_NAME  Login_Time \n");     
  149.     printf("----------------------------------\n");   
  150.     for(str = buffer, i = 0, n = 1; ; str = NULL, i++){  
  151.         subtoken = strtok(str, USER_DATA_TOK);  
  152.         if(subtoken == NULL)  
  153.             break;  
  154.         data[i] = subtoken;  
  155. #ifdef _DEBUG  
  156.         printf("> data[%d] = %s\n", i, subtoken);  
  157. #endif  
  158.         if(i != 0 && i % 2 == 0){  
  159.             printf(" %4s  %8s  %s\n", data[OFT_USR_ID], data[OFT_USR_NM], time2str(atol(data[OFT_LOGIN_TM]), time_buf));      
  160.             n++;  
  161.             i = -1;  
  162.         }  
  163.     }  
  164. }  
  165.   
  166. void * receiver_looper(void * p){  
  167.     if(userid == 0)  
  168.         return NULL;  
  169.     char * data[DATA_LEN];  
  170.     char * str, *subtoken;  
  171.     int i;  
  172.     while(1){  
  173.         if(msgrcv(msgid, &msg_rcv, sizeof(msg_rcv), userid, 0) < 0){  
  174.             perror("msgrcv");  
  175.             continue;  
  176.         }else{  
  177.   
  178. #ifdef _DEBUG  
  179.             printf("%s received: %s\n", __func__, msg_rcv.buffer);  
  180. #endif  
  181.             memset(data, NULL, sizeof(data));  
  182.             for(str = msg_rcv.buffer, i = 0; ; str = NULL, i++){  
  183.                 subtoken = strtok(str, DATA_TOK);  
  184.                 if(subtoken == NULL)  
  185.                     break;  
  186.                 data[i] = subtoken;  
  187. #ifdef _DEBUG  
  188.                 printf("> data[%d] = %s\n", i, subtoken);  
  189. #endif  
  190.             }  
  191.             // process received data  
  192.             // data format error  
  193.             if(i != DATA_LEN)  
  194.                 continue;  
  195.   
  196.             switch(data[OFT_CMD][0]){  
  197.             case CMD_LIST:  
  198.                 if(strcmp(data[OFT_FRM], TYPE_SERVER_STR)){  
  199.                     continue;  
  200.                 }  
  201.                 format_user_list(data[OFT_DAT]);  
  202.                 break;  
  203.             case CMD_LOGOUT:  
  204.                 if(strcmp(data[OFT_FRM], TYPE_SERVER_STR)){  
  205.                     continue;  
  206.                 }  
  207.                 printf("> %s ", data[OFT_DAT]);  
  208.                 printf("%s\n", time2str(atol(data[OFT_TIM]), data[OFT_DAT]));  
  209.                 exit(0);  
  210.             case CMD_CHAT:      // print chat content  
  211.                 printf("\n%s \n\t\t", data[OFT_DAT]);  
  212.                 printf("%s\n", time2str(atol(data[OFT_TIM]), data[OFT_DAT]));  
  213.                 printf("\n%s# ", name);  
  214.                 fflush(stdout);  
  215.                 break;  
  216.             case CMD_SEND_FILE:  
  217.                 break;  
  218.             }  
  219.         }  
  220.     }  
  221. }  
  222.   
  223.   
  224. int main(int argc, char **argv)      
  225. {      
  226.     signal(SIGINT, func);  
  227.     //  signal(SIGQUIT, func);  
  228.   
  229.     msgid = init_msg_queue();  
  230.   
  231.     pthread_t thread;  
  232.     // print help menu  
  233.     print_menu();  
  234.     while(1){  
  235.         switch(get_choice()){  
  236.         case 'i':  
  237.             if(login() == OK)  
  238.                 while(pthread_create(&thread, NULL, receiver_looper, NULL) < 0);  
  239.             break;  
  240.         case 'l':  
  241.             send_server(CMD_LIST, "List");  
  242.             sleep(1);  
  243.             break;  
  244.         case 'o':  
  245.             if(logout() == OK){  
  246.                 pthread_join(thread, NULL);  
  247.                 return 0;  
  248.             }else{  
  249.                 printf("Not login quit\n");  
  250.                 return 0;  
  251.             }  
  252.             break;  
  253.         case 'c':  
  254.             chat();  
  255.             break;  
  256.         case 'a':  
  257.             chat_all();  
  258.             break;  
  259.             break;  
  260.         case 'h':  
  261.             print_menu();  
  262.             break;  
  263.         case 'f':  
  264.             break;  
  265.         }  
  266.     }  
  267. }       

举报

相关文章推荐

基于Socket的多线程聊天室

使用Socket,并利用多线程,实现群聊通讯。客户端和服务端都应该使用多线程,服务端多线程负责多个客户端的连接和信息转发,客户端的多线程负责每个客户端的信息接受与发送。用一个list保存每个客户端的s...

c++消息队列的实现

消息队列 多线程 线程池

精选:深入理解 Docker 内部原理及网络配置

网络绝对是任何系统的核心,对于容器而言也是如此。Docker 作为目前最火的轻量级容器技术,有很多令人称道的功能,如 Docker 的镜像管理。然而,Docker的网络一直以来都比较薄弱,所以我们有必要深入了解Docker的网络知识,以满足更高的网络需求。

多线程聊天室的实现 C++

使用MFC进行网络编程,实现多线程聊天室 1.MFC网络编程要包含库文件 #include ,可以在stdafx.h中包含此文件 2.MFC套接字的初始化可以用AfxSocketInit()这个...

基于Socket/ServerSocket多线程实现的聊天室[附源代码]

主要说明的是:1.服务器端开启3个线程:主线程进行端口监听,第一个子线程由主线程派生出来,用来遍历所有已接入的客户端,第二个线程由第一个子线程派生出来,用来将客户端发送的信息转发给所有的客户端,第二个...

Linux下基于socket和多线程的聊天室小程序

要求:基于TCP编写,一个聊天室最多100人。 客户端:   1、用户需要登录,登录时只需要输入一个昵称即可无需判断昵称是否重复(如果其他功能都ok考虑)   2、用户登录后连接服务器端,进入聊...

基于Socket和多线程编程的聊天程序实现

Java最后一道作业题竟然是写个多线程聊天工具。以前在一次实训中做过linux版的。当时就有人说Java版的实现比较简单,如今看来确实有理。尤其是在做UI上,不用像gtk那么麻烦。先将我搜到的资源与大...

udp多线程实现聊天室

udp多线程实现聊天室

Python:多线程、消息队列编程

用多线程来做文件读写、网络交互,以大大提高效率,实测速度从一个小时25分钟  移除python ​终于搞定了多线程,很爽。​ 这个让我很烦 Exception in threa...

多线程及聊天室程序

1.一个多线程程序 新建一个win32 console application,取名:MultiThread,选空的工程,并建立一个名为MultiThread的源文件编辑: #incl...

基于Linux C的聊天室客户端(三)多线程

上次说到如何去解决解析xml格式响应的wen't
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)