基于Linux的进程聊天室,基于Linux的消息队列及多线程编程实现的聊天室(一)...

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

原理:

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

主要实现了以下功能:

1.通过多个终端登录,不同终端上登录用户实现私聊

2.群聊

3.查看在线用户

4.简单注册(没有实现用户保存,类似于公共聊天室)

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

>> 服务器通过特定的类型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;

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

运行情况如下:

75dad073e9db92674d539d4e7bf21e79.png

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

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

d91007715d84d3696b204fb46dac65ff.png

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

cdfdb7c5f347a843450f1702d72daa46.png

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

b446cab633eb5163357c107f3eb727d5.png

私聊:

c1870b14301e12496ea5679070c3a345.png

另外一个终端收到信息:

e7d5976464594c89b1907f475f9f082c.png

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

bc5c2f778eecd01dcb4e3f6b1c1983b0.png

d08074ac14ce67baf2cdecfc760ded58.png

退出:

cabd514d5f28133bc7015308e9a4e914.png

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值