本程序主要是针对Linux IPC通信初学者对Linux下消息队列通信机制,多线程编程,字符串处理,链表操作,信号简单处理等基本概念的练习。
原理:
消息队列是System V支持一种IPC机制,通过类似链表的操作向一个FIFO里通过msgsnd发送用户自定义数据,进程可以通过msgrcv来接收指定类似mtype的数据,从而实现进程间通信。
主要实现了以下功能:
- > 通过多个终端登录,不同终端上登录用户实现私聊
- > 群聊
- > 查看在线用户
- > 简单注册(没有实现用户保存,类似于公共聊天室)
下面是几种操作的处理流程分析。详细代码分析见下篇博文:
http://blog.csdn.net/mr_raptor/article/details/8484822
代码下载:
http://download.csdn.net/detail/mr_raptor/4976808
>> 服务器通过特定的类型mtype:1000,从消息队列上接收数据。
>> 当前登录用户将随机产生(random())的一个随机ID号作为申请用户ID,使用如下协议向服务器(mtype=1000)发送申请消息。
@msg.h
协议数据定义如下,共有4个段,以“:”作为分隔符。
- // CMD:FROM:TIME:DATA
- #define DATA_LEN 4
- #define OFT_CMD 0
- #define OFT_FRM 1
- #define OFT_TIM 2
- #define OFT_DAT 3
- #define DATA_TOK ":"
CMD:FROM:TIME:DATA
CMD:表示执行的操作
FROM:表示来自哪个终端
TIME:申请时间
DATA:用户发送数据
>> 服务器在接收到用户申请请求后,从可用ID里取出可用ID号(可用ID从START_ID开始向上累加)分配给新申请用户,将其加入到服务器维护的链表里,然后将新分配ID号写回到客户端(使用客户端随机产生的ID号写回),并且以后通信都通过新的ID号作用消息队列的mtype。
@msg.h
- #define START_ID 1
@msg_client.c
- if(login() == OK)
- while(pthread_create(&thread, NULL, receiver_looper, NULL) < 0);
- break;
- 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 _DEBUG
- printf("%s received: %s\n", __func__, msg_rcv.buffer);
- #endif
- memset(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 _DEBUG
- printf("> data[%d] = %s\n", i, subtoken);
- #endif
- }
- // process received data
- // data format error
- if(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 content
- printf("\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;
- }
- }
>> 群聊消息发送给服务器,服务器收到后,遍历在线链表,向每个在线用户发送消息。
@msg_svr.c
下面是分支处理代码片段:
- case CMD_TOALL:
- // send to all online client
- p = (&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;
注:本程序只能运行在一个主机上不同终端之间,不能实现跨主机通信。