当前位置: > 华清远见教育科技集团 > 嵌入式学习 > 讲师博文 > 基于Linux的消息队列及多线程编程实现的聊天室(一)
基于Linux的消息队列及多线程编程实现的聊天室(一)
时间:2016-12-12作者:华清远见

本程序主要是针对Linux IPC通信初学者对Linux下消息队列通信机制,多线程编程,字符串处理,链表操作等基本概念的练习。

原理:

消息队列是System V支持一种IPC机制,通过类似链表的操作向一个FIFO里通过msgsnd发送用户自定义数据,进程可以通过msgrcv来接收指定类似mtype的数据,从而实现进程间通信。

主要实现了以下功能:
        1.通过多个终端登录,不同终端上登录用户实现私聊
        2.群聊
        3.查看在线用户
        4.简单注册(没有实现用户保存,类似于公共聊天室)

脉冲宽度调制(PWM)功能是使用TCMPBn寄存器的值来实现的。在定时器控制逻辑中,如果递减计数器的值 匹配 比较寄存器的值,定时器的控制逻辑将更改输出的状态。因此,比较寄存器决定了一个PWM输出开始时间(或关闭时间)。

下面是几种操作的处理流程分析。详细代码分析见下篇博文:
                //blog.csdn.net/mr_raptor/article/details/8484822

代码下载:
                //download.csdn.net/detail/mr_raptor/4976808

>> 服务器通过特定的类型mtype:1000,从消息队列上接收数据。
        >> 当前登录用户将随机产生(random())的一个ID号作为申请,如下协议向服务器1000发送申请消息。

@msg.h
        [cpp] view plaincopyprint?
                1. // CMD:FROM:TIME:DATA
                2. #define        DATA_LEN        4
                3. #define        OFT_CMD        0
                4. #define        OFT_FRM        1
                5. #define        OFT_TIM        2
                6. #define        OFT_DAT        3
                7. #define        DATA_TOK        ":"

CMD:FROM:TIME:DATA
        CMD:表示执行的操作
        FROM:表示来自哪个终端
        TIME:申请时间
        DATA:用户发送数据

>> 服务器在接收到用户申请请求后,加入到服务器维护的链表里,然后从可用ID里取出可用ID号分配给新申请用户,以后通信都通过新的ID号作用消息队列的mtype。

@msg.h
        [cpp] view plaincopyprint?
        1.#define        START_ID        1

>> 登录用户接收到服务器分配的新ID后,开启接收消息线程等待接收来自消息队列里,并且发送能自己的消息。

@msg_client.c
        [cpp] view plaincopyprint?
        1.login();
        2.while(pthread_create(&thread, NULL, receiver_looper, NULL) < 0);
        3.break;

[cpp] view plaincopyprint?
        1.void * receiver_looper(void * p){
        2.        if(userid == 0)
        3.        return NULL;
        4.        char * data[DATA_LEN];
        5.        har * str, *subtoken;
        6.        int i;
        7.        while(1){
        8.        if(msgrcv(msgid, &msg_rcv, sizeof(msg_rcv), userid, 0) < 0){
        9.        perror("msgrcv");
        10.        continue;
        11.        }else{

>> 当用户在消息队列上收到消息后,按照前面说的通信协议解析(strtok())接收到的数据,格式化后依据不同的CMD操作用于分支处理。

[cpp] view plaincopyprint?
        1. #ifdef _DEBUG
        2. printf("%s received: %s\n", __func__, msg_rcv.buffer);
        3. #endif
        4. memset(data, NULL, sizeof(data));
        5. for(str = msg_rcv.buffer, i = 0; ; str = NULL, i++){
        6. subtoken = strtok(str, DATA_TOK);
        7. if(subtoken == NULL)
        8. break;
        9. data[i] = subtoken;
        10. #ifdef _DEBUG
        11. printf("> data[%d] = %s\n", i, subtoken);
        12. #endif
        13. }
        14. // process received data
        15. // data format error
        16. if(i != DATA_LEN)
        17. continue;
        18.         19. switch(data[OFT_CMD][0]){
        20. case CMD_LIST:
        21. if(strcmp(data[OFT_FRM], TYPE_SERVER_STR)){
        22. continue;
        23. }
        24. format_user_list(data[OFT_DAT]);
        25. break;
        26. case CMD_LOGOUT:
        27. if(strcmp(data[OFT_FRM], TYPE_SERVER_STR)){
        28. continue;
        29. }
        30. printf("> %s ", data[OFT_DAT]);
        31. printf("%s\n", time2str(atol(data[OFT_TIM]), data[OFT_DAT]));
        32. exit(0);
        33. case CMD_CHAT: // print chat content
        34. printf("\n%s \n\t\t", data[OFT_DAT]);
        35. printf("%s\n", time2str(atol(data[OFT_TIM]), data[OFT_DAT]));
        36. printf("\n%s# ", name);
        37. fflush(stdout);
        38. break;
        39. case CMD_SEND_FILE:
        40. break;
        41. }
        42. }

>> 群聊消息发送给服务器,服务器收到后,遍历在线链表,向每个在线用户发送消息。 @msg_svr.c

下面是分支处理代码片段:

[cpp] view plaincopyprint?
        1. case CMD_TOALL:
        2. // send to all online client
        3. p = (&msg_list_head)->next;
        4. while(p){
        5. u= (struct user*)p;
        6. send_msg(u->id, CMD_CHAT, data[OFT_FRM], data[OFT_DAT]);
        7. p = p->next;
        8. }
        9. break;

注:本程序只能运行在一个主机上不同终端之间,不能实现跨主机通信。

运行情况如下:

主要打印客户端的用户操作,消息转发等信息。

客户端登录:初始帮助信息

用户登录及列出在线用户:

另外一个终端登录luccy用户,列出在线用户:

私聊:

另外一个终端收到信息:

群聊,两个终端都收到信息:

退出:

另外还有文件传输功能,留给同学们自己去实现吧。

发表评论
评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)