基于消息队列的C/S通信

程序示意图:



程序思路:

         分别写客户端和服务端的函数,在主任务中创建两个client和一个server,考虑到实际情况,应该server的优先级高并且先用taskSpawn函数创建server任务。然后等待客户端获得服务端的应答,则删除队列,程序结束。为了演示client请求,server应答的过程,本次实验采取client发送时发送一个value,在创建任务时给定,每次请求时value加一,服务端获得value之后将该值加一,并根据客户端的id,返回给相应的响应队列。Client函数中首先根据请求队列的大小发送数据,然后开始等待接收响应队列的返回结果。Server函数中等待请求队列不为空,获得请求并返回给对应的响应队列。


关键代码:

main.h
#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED
#include "vxWorks.h"
#include "semLib.h"
#include "taskLib.h"
#include "msgQLib.h"
#include "sysLib.h"
#include "stdio.h"
#define  CLIENT_TASK_PRI          99
#define  SERVER_TASK_PRI          98
#define  TASK_STACK_SIZE          5000
struct msg
{
    int id;
    int value;
};
LOCAL MSG_Q_ID requestQId;
LOCAL MSG_Q_ID response1QId;
LOCAL MSG_Q_ID response2QId;

LOCAL BOOL notDone;
LOCAL int numMsg = 3;
LOCAL STATUS clientTask (int cid, int value);
LOCAL STATUS serverTask(void);
#endif // MAIN_H_INCLUDED

#include "main.h"
STATUS clientTask(int cid, int value)
{
    int i, j, k;
    struct msg request_msg, response_msg;
    printf ("clientTask started: cid = %d\n", cid);
    for(i=0; i<numMsg; i++)
    {
		request_msg.id = cid;
		request_msg.value = value+i;
       /* semTake(request_semMutex, WAIT_FOREVER);*/
        if (( msgQSend (requestQId, (char *) &request_msg, sizeof (request_msg),
                        WAIT_FOREVER,  MSG_PRI_NORMAL)) == ERROR)
        {
            perror ("Error in sending the message to request queue\n");
            return (ERROR);
        }
        else
        {
            printf ("clientTask: cid = %d, value = %d \n",
                    cid, value+i);
        }
        /*semGive(request_semMutex);*/
    }
/*接收数据从responseQ*/
    if(1 ==  cid)
    {
        for(j=0; j<numMsg; j++)
        {
           /* semTake(response1_semMutex, WAIT_FOREVER);*/
            if (( msgQReceive (response1QId, (char *) &response_msg,
                               sizeof (response_msg), WAIT_FOREVER)) == ERROR)
            {
                perror ("Error in receiving the response1 message\n");
                return (ERROR);
            }
            else
            {
                printf ("clientTask: get msg of value %d from cid = %d\n",
                        response_msg.value, response_msg.id);
            }
        /*    semGive(response1_semMutex);*/
        }

    }
    else if(2 == cid)
    {
        for(k=0; k<numMsg; k++)
        {
       /*     semTake(response2_semMutex, WAIT_FOREVER);*/
            if (( msgQReceive (response2QId, (char *) &response_msg,
                               sizeof (response_msg), WAIT_FOREVER)) == ERROR)
            {
                perror ("Error in receiving the response2 message\n");
                return (ERROR);
            }
            else
            {
                printf ("clientTask: get msg of value %d from cid = %d\n",
                        response_msg.value, response_msg.id);
            }
         /*   semGive(response2_semMutex);*/
        }

    }
	else
	{
		printf("clientTask: cid error!\n");
	}
    notDone = FALSE;
    return (OK);
}

STATUS serverTask(void)
{
	int i;
    struct msg response_msg ;
    printf ("\nserverTask Started \n");
	for(i=0; i<numMsg*2; i++)
	{
	/*	semTake(request_semMutex, WAIT_FOREVER);*/
		if (( msgQReceive (requestQId, (char *) &response_msg,
                       sizeof (response_msg), WAIT_FOREVER)) == ERROR)
		{
			perror ("Error in receiving the message\n");
			return (ERROR);
		}
		else
		{
			printf ("serverTask: get msg of value %d from cid = %d\n",
					response_msg.value, response_msg.id);
		}
		/*semGive(request_semMutex);*/
		/*将获得的value加一后,根据cid发给相应的应答序列*/
		response_msg.value += 1;
		if(response_msg.id==1)
		{
			/*semTake(response1_semMutex, WAIT_FOREVER);*/
			if (( msgQSend (response1QId, (char *) &response_msg, sizeof (response_msg),
							WAIT_FOREVER,  MSG_PRI_NORMAL)) == ERROR)
			{
				perror ("Error in sending the message to response1 queue\n");
				return (ERROR);
			}
			else
			{
				printf ("serverTask sending to response Q1: value = %d \n",
						response_msg.value);
			}
			/*semGive(response1_semMutex);*/
		}
		else if(response_msg.id==2)
		{
			/*semTake(response2_semMutex, WAIT_FOREVER);*/
			if (( msgQSend (response2QId, (char *) &response_msg, sizeof (response_msg),
							WAIT_FOREVER,  MSG_PRI_NORMAL)) == ERROR)
			{
				perror ("Error in sending the message to response2 queue\n");
				return (ERROR);
			}
			else
			{
				printf ("serverTask sending to response Q2: value = %d \n",
						response_msg.value);
			}
			/*semGive(response2_semMutex);*/
		}
		else
		{
			printf("error in response_msg, the id = %d\n", response_msg.id);
		}
	}    
    return (OK);
}

STATUS main()
{
    notDone = TRUE;
   /* request_semMutex = semBCreate(SEM_Q_FIFO, SEM_FULL);
    response1_semMutex = semBCreate(SEM_Q_FIFO, SEM_FULL);
    response2_semMutex = semBCreate(SEM_Q_FIFO, SEM_FULL);*/
    if ((requestQId = msgQCreate(numMsg*2, sizeof (struct msg), MSG_Q_FIFO)) == NULL)
    {
        perror ("Error in creating requestQ");
        return (ERROR);
    }
    if ((response1QId = msgQCreate(numMsg, sizeof (struct msg), MSG_Q_FIFO)) == NULL)
    {
        perror ("Error in creating response1Q");
        return (ERROR);
    }
    if ((response2QId = msgQCreate(numMsg, sizeof (struct msg), MSG_Q_FIFO)) == NULL)
    {
        perror ("Error in creating response2Q");
        return (ERROR);
    }
	if (taskSpawn (" tserverTask ", SERVER_TASK_PRI, 0, TASK_STACK_SIZE,
                   (FUNCPTR) serverTask, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
    {
        perror ("serverTask: Error in spawning serverTask");
        return (ERROR);
    }
    if (taskSpawn (" tclientTask ", CLIENT_TASK_PRI, 0, TASK_STACK_SIZE,
                   (FUNCPTR) clientTask, 1, 10, 0, 0, 0, 0, 0, 0, 0, 0)  == ERROR)
    {
        perror ("clientTask: Error in spawning clientTask1");
        return (ERROR);
    }
    if (taskSpawn (" tclientTask ", CLIENT_TASK_PRI, 0, TASK_STACK_SIZE,
                   (FUNCPTR) clientTask, 2, 10, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
    {
        perror ("clientTask: Error in spawning clientTask2");
        return (ERROR);
    }
	
    while (notDone)
    {
        taskDelay (sysClkRateGet ());     
    }
	 	if (msgQDelete(requestQId) == ERROR || msgQDelete(response1QId) == ERROR ||
           msgQDelete(response2QId) == ERROR)
        {
            perror ("Error in deleting msgQs");
            return (ERROR);
        }
    return (OK);
}

实验结果:


    可以看出,首先进入了server任务,然后进入client任务,client发送给请求队列消息后,服务端立刻获得value值,因为server优先级高,所以打印发送信息也是在server阻塞后打印的,并且能够看出serverl立刻向相应的响应队列发送了消息,此时value的值比client发过来的值多一,符合程序的设计,后来也是如此。直到client1的请求都被响应了,client1从自己的响应队列中得到加一后的值,之后client2也同理。

下面是windview演示结果:

第一幅能看出t1即主任务创建了三个任务,然后切换到Server,但是server被阻塞,因为请求队列为空,又切换到client1,当client1有请求之后再切换到server给予响应,依次进行,client2也是如此。



下图是过了一段时间的截图,因为主程序一直在等待客户端接收到响应队列的消息,结束之后能从下图看出删除了请求队列和响应队列1,响应队列2,程序结束。


遇到问题:

1、  C语言的单行注释“//”不能使用,编译不能通过。

2、  刚开始使用二进制信号量控制队列只能有一个任务在发送或接受,造成死锁。发送之前将请求队列take,然后发送,由于server优先级高,此时还没有来得及释放信号量就切换到server任务,server接收请求队列获取不到信号量,造成一直等待的死锁局面。

3、  刚开始没有考虑实际情况,先创建了client1,client2,并且优先级设定为一致,而事实上应该先启动服务器在允许客户端请求,故更改顺序,先创建server任务。

4、用windview观察的时候要选择task state transition,刚开始使用默认的context switch观察不到想要的结果。之后观察成功,鼠标悬停就能看到相关的信息,非常方便。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
消息队列是一种进程间通信的方式,可以用于不同进程之间的通信。它基于消息的异步传递,即一个进程把消息放入消息队列中,而另一个进程从队列中获取消息。 实现消息队列的主要步骤如下: 1. 创建消息队列。创建消息队列需要指定消息队列的键值和权限等信息。 2. 发送消息。在发送消息时,需要指定消息队列的标识符、消息类型和消息内容等信息。 3. 接收消息。在接收消息时,需要指定消息队列的标识符和消息类型等信息。 以下是一个使用消息队列实现进程间通信的简单示例: ```c #include <stdio.h> #include <stdlib.h> #include <sys/msg.h> #include <unistd.h> #define MSG_SIZE 1024 typedef struct { long type; char text[MSG_SIZE]; } message; int main() { int msgid; key_t key; message msg; // 创建消息队列 key = ftok(".", 'a'); if ((msgid = msgget(key, IPC_CREAT|0666)) == -1) { perror("msgget error"); exit(1); } // 发送消息 msg.type = 1; sprintf(msg.text, "Hello, this is message from process %d", getpid()); if (msgsnd(msgid, &msg, sizeof(msg.text), 0) == -1) { perror("msgsnd error"); exit(1); } // 接收消息 if (msgrcv(msgid, &msg, sizeof(msg.text), 1, 0) == -1) { perror("msgrcv error"); exit(1); } printf("Received message: %s\n", msg.text); // 删除消息队列 if (msgctl(msgid, IPC_RMID, NULL) == -1) { perror("msgctl error"); exit(1); } return 0; } ``` 该示例中,首先创建一个消息队列,然后在发送进程中向消息队列中发送一条消息,接收进程从消息队列中接收消息并输出。最后删除消息队列。注意,发送和接收进程需要共享消息队列的标识符,可以通过 ftok() 函数生成一个唯一的键值来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值