MQTT并发测试(Linux嵌入式环境)

发布者代码:

#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "MQTTClient.h"

#define ADDRESS     "tcp://localhost:1883"
#define CLIENTID    "ExampleClientPub"
#define TOPIC       "MQTT Examples"
#define PAYLOAD     "Hello World!"
#define QOS         1
#define TIMEOUT     10000L


int GetSec(void)
{
	struct timeval tv;

	gettimeofday(&tv,NULL);

	//printf("GetSec: sec=%d, usec=%d\n", tv.tv_sec, tv.tv_usec);

	//printf("start sec=%ld, mill_sec=%ld, micr_sec=%ld\n", \
	//	tvBef.tv_sec, tvBef.tv_sec*1000 + tvBef.tv_usec/1000, tvBef.tv_sec*1000000 + tvBef.tv_usec);	

	return tv.tv_sec;

}

int GetMillSec(void)
{
	struct timeval tv;

	gettimeofday(&tv,NULL);

	//printf("GetMillSec: sec=%d, usec=%d\n", tv.tv_sec, tv.tv_usec);

	//printf("start sec=%ld, mill_sec=%ld, micr_sec=%ld\n", \
	//	tvBef.tv_sec, tvBef.tv_sec*1000 + tvBef.tv_usec/1000, tvBef.tv_sec*1000000 + tvBef.tv_usec);	

	return tv.tv_sec*1000 + tv.tv_usec/1000;
}

int GetMirc(void)
{
	struct timeval tv;

	gettimeofday(&tv,NULL);

	//printf("GetMirc: sec=%d, usec=%d\n", tv.tv_sec, tv.tv_usec);

	//printf("start sec=%ld, mill_sec=%ld, micr_sec=%ld\n", \
	//	tvBef.tv_sec, tvBef.tv_sec*1000 + tvBef.tv_usec/1000, tvBef.tv_sec*1000000 + tvBef.tv_usec);	

	return tv.tv_sec*1000000 + tv.tv_usec;

}

typedef struct{
	int iThrdId; //线程ID
	int iTestCnt; //测试次数
}ThrdPara;

int main_thread(void* argv)
{
    MQTTClient client;
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    MQTTClient_message pubmsg = MQTTClient_message_initializer;
    MQTTClient_deliveryToken token;
    int rc, iCnt;
	int iBf, iAf;
	char szClientId[32];
	char payload[128];
	ThrdPara *pThrdPara;


	pThrdPara = (ThrdPara*)argv;
	printf("main_thread: pThrdPara->iThrdId=%d, pThrdPara->iTestCnt=%d.\n", pThrdPara->iThrdId, pThrdPara->iTestCnt);

	//用户ID,每个发布消息的客户端都不一样!
	memset(szClientId, 0, sizeof(szClientId));
	sprintf(szClientId, "%c", pThrdPara->iThrdId);

	//待发布的负载数据,通过线程号来区分
	memset(payload, 0, sizeof(payload));
	sprintf(payload, "hello world! thrd-%d", pThrdPara->iThrdId);
	printf("payload: %s\n", payload);

	//创建MQTT客户端,绑定服务器地址、客户端ID
//    MQTTClient_create(&client, ADDRESS, CLIENTID,
	  MQTTClient_create(&client, ADDRESS, szClientId,
        MQTTCLIENT_PERSISTENCE_NONE, NULL);
    conn_opts.keepAliveInterval = 20;
    conn_opts.cleansession = 1;

	//connect服务端
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        exit(EXIT_FAILURE);
    }
	iCnt = 0;
	printf("--------------------pThrdPara->iThrdId=%d, iCnt=%d----------------------\n", pThrdPara->iThrdId, pThrdPara->iTestCnt);
	iBf = GetMirc();
	while (iCnt++ < pThrdPara->iTestCnt)
	{
		//发布消息
	    //pubmsg.payload = PAYLOAD;
	    //pubmsg.payloadlen = strlen(PAYLOAD);
	    pubmsg.payload = payload;
		pubmsg.payloadlen = strlen(payload);
	    pubmsg.qos = QOS;
	    pubmsg.retained = 0;
	    MQTTClient_publishMessage(client, TOPIC, &pubmsg, &token);
	    //printf("Waiting for up to %d seconds for publication of %s\n"
	    //        "on topic %s for client with ClientID: %s\n",
	    //        (int)(TIMEOUT/1000), PAYLOAD, TOPIC, CLIENTID);

		//等待消息发布完成
	    rc = MQTTClient_waitForCompletion(client, token, TIMEOUT);
	    //printf("Message with delivery token %d delivered\n", token);
		//printf("--------------------iCnt=%d----------------------\n", iCnt);
	}
	//计算消息发布所有的时间,单位微妙
	iAf = GetMirc();
	printf("thrd-%d, Interv time MircSec=%d.\n", pThrdPara->iThrdId, iAf-iBf);

    MQTTClient_disconnect(client, 10000);
    MQTTClient_destroy(&client);
    return rc;
}

//描述:主函数
//参数:@argc argv参数个数
//		@argv:
//				argv[1] 线程个数
//				argv[2] 单个线程通信的次数
//Example: ./MQTTClient_publish 3 100 
//			其中3表示运行3个线程,100表示每个线程发布100次消息
int main(int argc, char *argv[])
{
	ThrdPara *pThrdPara;
	pthread_t *pthrd;
	int iThrdNum;
	int iTestNum;
	int iThrdIdx;
	char szTestNumStr[16];
	char ch;

	if (argc != 3)
	{

		printf("main: Failed to argc, argc=%d\n", argc);
		exit(0);
	}

	//通过主函数的参数控制创建线程的个数、每个线程下的消息发布条数
	iThrdNum = atoi(argv[1]);
	iTestNum = atoi(argv[2]);
	printf("main: iThrdNum=%d, iTestNum=%d\n", iThrdNum, iTestNum);
	pthrd = malloc(sizeof(pthread_t)*iThrdNum);
	pThrdPara = malloc(sizeof(ThrdPara)*iThrdNum);
	for (iThrdIdx=0; iThrdIdx<iThrdNum; iThrdIdx++)
	{
		pThrdPara[iThrdIdx].iThrdId = iThrdIdx;
		pThrdPara[iThrdIdx].iTestCnt = iTestNum;
		pthread_create(&pthrd[iThrdIdx], NULL, &main_thread, (void *)&pThrdPara[iThrdIdx]);
//		sleep(5);
	}

	do  
	{ 
		ch = getchar(); 
	} while(ch!='Q' && ch != 'q'); 


	return NULL;
}

订阅者代码:

#include "stdio.h" 
#include "stdlib.h" 
#include "string.h" 
#include "MQTTClient.h" 

 
#define ADDRESS     "tcp://localhost:1883" 
#define CLIENTID    "ExampleClientSub" 
#define TOPIC       "MQTT Examples" 
#define PAYLOAD     "Hello World!" 
#define QOS         1 
#define TIMEOUT     10000L 

 
volatile MQTTClient_deliveryToken deliveredtoken; 

 
void delivered(void *context, MQTTClient_deliveryToken dt) 
{ 
    printf("Message with token value %d delivery confirmed\n", dt); 
    deliveredtoken = dt; 
} 
 
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message) 
{ 
	int i; 
	char* payloadptr; 
 
	printf("Message arrived\n"); 
	printf("     topic: %s\n", topicName); 
	printf("   message: ");  

	//按照我们的需求,需要在payload负载数据中携带对应数据的属性
	payloadptr = message->payload; 
	for(i=0; i<message->payloadlen; i++) 
	{ 
		putchar(*payloadptr++); 
	} 
	putchar('\n'); 
	MQTTClient_freeMessage(&message); 
	MQTTClient_free(topicName); 
	return 1; 
} 
 
void connlost(void *context, char *cause) 
{ 
	printf("\nConnection lost\n"); 
	printf("     cause: %s\n", cause); 
} 

int main(int argc, char* argv[]) 
{ 
	MQTTClient client; 
	MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; 
	int rc; 
	int ch; 

	//创建MQTT订阅客户端,绑定服务端地址、以及当前订阅者的用户ID(每个客户端的用户ID务必保证唯一性)
	MQTTClient_create(&client, ADDRESS, CLIENTID, 
	MQTTCLIENT_PERSISTENCE_NONE, NULL); 
	conn_opts.keepAliveInterval = 20; 
	conn_opts.cleansession = 1; 

	//绑定MQTT订阅者客户端的消息到达、消息发送的回调函数 
	MQTTClient_setCallbacks(client, NULL, connlost, msgarrvd, delivered); 
	 
	//MQTT订阅者客户端连接服务端 
	if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS) 
	{ 
		printf("Failed to connect, return code %d\n", rc); 
		exit(EXIT_FAILURE); 
	} 

	//提交订阅者给服务端
	printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n" 
		"Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS); 
	MQTTClient_subscribe(client, TOPIC, QOS); 

	 
	do  
	{ 
		ch = getchar(); 
	} while(ch!='Q' && ch != 'q'); 
	 
	 
	MQTTClient_disconnect(client, 10000); 
	MQTTClient_destroy(&client); 
	return rc; 
} 

makfile:

arm-linux-gnueabi-gcc MQTTClient_publish.c -o MQTTClient_publish -L./linux_mqtt_c -lpaho-mqtt3c -lpthread

arm-linux-gnueabi-gcc MQTTClient_subscribe.c -o MQTTClient_subscribe -L./linux_mqtt_c -lpaho-mqtt3c -lpthread

 

方案验证结果:由于发布者和订阅者的消息是同步的,以下消耗时间均指发布者和订阅者的时间;

验证方案1

进程

发送次数

发送消耗时间(us)

发布者进程1

100

10998389

发布者进程1

200

21997781

发布者进程1

500

55018353

结论:同一个进程发送100、200、500次所耗时间,平均每次发送时间为100ms;

验证方案2

进程

发送次数

发送消耗时间(us)

发布者进程1

100

10997878

发布者进程2

100

10999326

发布者进程1

200

22017567

发布者进程2

200

21997405

发布者进程1

500

54998293

发布者进程2

500

55007166

结论:不同进程同时发送100、200、500次所耗时间,平均每次发送时间为100ms;

总结:综合方案1和方案2,多个进程与单个进程的负载通信所耗时间相同,所以单个进程或多个进程对MQTT服务器的负载没有影响,但每次发布一次负载消息所耗时间为100ms,系统库无法用这种通信机制满足;

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值