linux下socket实现多个客户端向一个服务器端连续发送消息,服务器端使用MQTT转发消息

 左边同时启动了5个客户端,右边上面是server收界面client消息,右下方是mqtt subscruib 窗口。

本文的实现参考了几篇很不错的博客,下面列出给大家参考:

这是一个聊天室程序,实现多个客户端向一个服务端发送消息,服务端输入消息,可以向所有连接上的客户端广播。

  • linux下socket编程实现一个服务器连接多个客户端

linux下socket编程实现一个服务器连接多个客户端_skyaizl的博客-CSDN博客

  • C++基础--完善Socket C/S ,实现客户端,服务器端断开重连     

C++基础--完善Socket C/S ,实现客户端,服务器端断开重连_xqhrs232的博客-CSDN博客_c++ socket重连

  • 在ubuntu上安装,使用MQTT Mosquitto

在ubuntu上安装,使用MQTT Mosquitto_aFakeProgramer的博客-CSDN博客

  • Linux下学习用C语言实现MQTT(三)(异步函数)

Linux下学习用C语言实现MQTT(三)(异步函数)_Hanson_1999的博客-CSDN博客_c语言 异步函数

talk is cheap show me the code!

socket通信 client.cpp 代码:

使用多线程实现了client断开重连。

#include <stdio.h>    
#include <iostream>
#include <stdlib.h>    
#include <netinet/in.h>    
#include <sys/socket.h>    
#include <arpa/inet.h>    
#include <string.h>    
#include <unistd.h>
#include <thread>
  
#define BUFFER_SIZE 1024    


bool need_reconnect = false;    
//int main(int argc, const char * argv[])    
int client_connect(void) 
{    
    struct sockaddr_in server_addr;    
    server_addr.sin_family = AF_INET;    
    server_addr.sin_port = htons(11332);    
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    //server_addr.sin_addr.s_addr = inet_addr("192.168.232.153");
  
    bzero(&(server_addr.sin_zero), 8);    
    //创建套接字
    int server_sock_fd = socket(AF_INET, SOCK_STREAM, 0);    
    if(server_sock_fd == -1)    
    {    
        perror("socket error");    
        return 1;    
    }    

    char recv_msg[BUFFER_SIZE];    
    char input_msg[BUFFER_SIZE];    
    //连接服务器
    if(connect(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) == 0)    
    {   

        fd_set client_fd_set;    
        struct timeval tv;      
        while(1)    
        {    
            tv.tv_sec = 1;    
            tv.tv_usec = 0;    
            FD_ZERO(&client_fd_set);
            FD_SET(STDIN_FILENO, &client_fd_set);    
          //FD_SET(server_sock_fd, &client_fd_set);    
          
          //select(server_sock_fd += 1, &client_fd_set, NULL, NULL, &tv);    
           

            if(FD_ISSET(STDIN_FILENO, &client_fd_set))    
            {    
 
               bzero(input_msg, BUFFER_SIZE);    
              //fgets(input_msg, BUFFER_SIZE, stdin);
                strcpy(input_msg,"123456789 hello this test message Good news!!!!!!!!!!!");   
                //向服务端发送消息				
                if(send(server_sock_fd, input_msg, BUFFER_SIZE, 0) == -1)    
                {    
                    perror("Client send message error due to socket server program shutdown!\n");
                    need_reconnect = true;
                    return 0;    
                }
                need_reconnect = false;    
            }    
            if(FD_ISSET(server_sock_fd, &client_fd_set))    
            {    
                bzero(recv_msg, BUFFER_SIZE);
                //接收来自服务端的消息				
                long byte_num = recv(server_sock_fd, recv_msg, BUFFER_SIZE, 0);    
                if(byte_num > 0)    
                {    
                    if(byte_num > BUFFER_SIZE)    
                    {    
                        byte_num = BUFFER_SIZE;    
                    }    
                    recv_msg[byte_num] = '\0';    
                    printf("服务器:%s\n", recv_msg);    
                }else if(byte_num < 0)    
                {    
                    printf("接受消息出错!\n");    
                }else    
                {    
                    printf("服务器端退出!\n");    
                    exit(0);    
                }    
            }    
                
        }    
    }    
    return 0;    
}

void reconnect()
{
   int count =0;
   while(1)
  {
  
        if(need_reconnect)
        {
            client_connect();
            int left_time = (5-count);
            printf("reconnect 10s 1 times,left time: %d",left_time);
            count++;
        }
        sleep(10);

        if(count>4)
        {
           break;
        }
   }
 
   return;

}
   

int main(int argc, const char * argv[])    
{    
    std::thread th1(client_connect);

    std::thread th2(reconnect);

    th1.detach();

    th2.join();    
    
    return 0;    
} 

socket通信server.cpp和mqtt client publish的代码

#include<stdio.h>    
#include<stdlib.h>    
#include<netinet/in.h>    
#include<sys/socket.h>    
#include<arpa/inet.h>    
#include<string.h>    
#include<unistd.h>  

//mqtt head file
#include "MQTTAsync.h"
#include <mutex>
#include <thread>
  
#define BACKLOG 5          //完成三次握手但没有accept的队列的长度    
#define CONCURRENT_MAX 8   //应用层同时可以处理的连接    
#define SERVER_PORT 11332    
#define BUFFER_SIZE 1024    
#define QUIT_CMD ".quit"  

//mqtt define
#define ADDRESS     "tcp://localhost:1883"
#define CLIENTID    "clientPub"
#define TOPIC       "MQTT xxx"
//#define PAYLOAD     "Hello World!"
#define QOS         1
#define TIMEOUT     10000L
volatile MQTTAsync_token deliveredtoken;

int finished = 0;
bool is_connect = false;
long byte_num =0;
//socket 
int client_fds[CONCURRENT_MAX]; 
char input_msg[BUFFER_SIZE];    
char recv_msg[BUFFER_SIZE];

int rsu_server()
{
	std::mutex my_mutex;
	//本地地址    
    struct sockaddr_in server_addr;    
    server_addr.sin_family = AF_INET;    
    server_addr.sin_port = htons(SERVER_PORT);    
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");    
    bzero(&(server_addr.sin_zero), 8);    
    //创建socket    
    int server_sock_fd = socket(AF_INET, SOCK_STREAM, 0);    
    if(server_sock_fd == -1)    
    {    
        perror("socket error");    
        return 1;    
    }    
    //绑定socket    
    int bind_result = bind(server_sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr));    
    if(bind_result == -1)    
    {    
        perror("bind error");    
        return 1;    
    }    
    //listen    
    if(listen(server_sock_fd, BACKLOG) == -1)    
    {    
        perror("listen error");    
        return 1;    
    }    
    //fd_set    
    fd_set server_fd_set;    
    int max_fd = server_sock_fd;    
    struct timeval tv;  //超时时间设置
    while(1)    
    {    
        tv.tv_sec = 10;    
        tv.tv_usec = 0;    
        FD_ZERO(&server_fd_set); 
        //add standard input		
        FD_SET(STDIN_FILENO, &server_fd_set);    
       
        if(max_fd <STDIN_FILENO)    
        {    
            max_fd = STDIN_FILENO;    
        }    
        printf("STDIN_FILENO=%d\n", STDIN_FILENO);    
        //服务器端socket    
        FD_SET(server_sock_fd, &server_fd_set);    
        printf("server_sock_fd=%d\n", server_sock_fd);    
        if(max_fd < server_sock_fd)    
        {    
            max_fd = server_sock_fd;    
        }    
        //客户端连接    
        for(int i =0; i < CONCURRENT_MAX; i++)    
        {    
            printf("client_fds[%d]=%d\n", i, client_fds[i]);    
            if(client_fds[i] != 0)    
            {    
                FD_SET(client_fds[i], &server_fd_set);    
                if(max_fd < client_fds[i])    
                {    
                    max_fd = client_fds[i];    
                }    
            }    
        } 
        //printf("before select");   
        int ret = select(max_fd + 1, &server_fd_set, NULL, NULL, &tv);
        printf("select ret=%d",ret);    
        if(ret < 0)    
        {    
            perror("select 出错\n");    
            continue;    
        }    
        else if(ret == 0)    
        {    
            printf("select 超时\n");    
            continue;    
        }    
        else    
        {    
            //ret 为未状态发生变化的文件描述符的个数    
            if(FD_ISSET(STDIN_FILENO, &server_fd_set))    
            {    
                printf("发送消息:\n");    
                bzero(input_msg, BUFFER_SIZE);    
                fgets(input_msg, BUFFER_SIZE, stdin);    
                //输入“.quit"则退出服务器    
                if(strcmp(input_msg, QUIT_CMD) == 0)    
                {    
                    exit(0);    
                }    
                for(int i = 0; i < CONCURRENT_MAX; i++)    
                {    
                    if(client_fds[i] != 0)    
                    {    
                        printf("client_fds[%d]=%d\n", i, client_fds[i]);    
                        send(client_fds[i], input_msg, BUFFER_SIZE, 0);    
                    }    
                }    
            } 
   
            if(FD_ISSET(server_sock_fd, &server_fd_set))    
            {    
                //有新的连接请求    
                struct sockaddr_in client_address;    
                socklen_t address_len;    
                int client_sock_fd = accept(server_sock_fd, (struct sockaddr *)&client_address, &address_len);    
                printf("new connection client_sock_fd = %d\n", client_sock_fd);    
                if(client_sock_fd > 0)    
                {    
                    int index = -1;    
                    for(int i = 0; i < CONCURRENT_MAX; i++)    
                    {    
                        if(client_fds[i] == 0)    
                        {    
                            index = i;    
                            client_fds[i] = client_sock_fd;    
                            break;    
                        }    
                    }    
                    if(index >= 0)    
                    {    
                        printf("新RSU客户端(%d)加入成功 %s:%d\n", index, inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));    
                    }    
                    else    
                    {    
                        bzero(input_msg, BUFFER_SIZE);    
                        strcpy(input_msg, "服务器加入的RSU客户端数达到最大值,无法加入!\n");    
                        send(client_sock_fd, input_msg, BUFFER_SIZE, 0);    
                        printf("客户端连接数达到最大值,新RSU客户端加入失败 %s:%d\n", inet_ntoa(client_address.sin_addr), ntohs(client_address.sin_port));    
                    }    
                }    
            }
    
            for(int i =0; i < CONCURRENT_MAX; i++)    
            {    
                if(client_fds[i] !=0)    
                {    
                    if(FD_ISSET(client_fds[i], &server_fd_set))    
                    {    
                        //处理某个RSU客户端过来的消息-------------    
                        bzero(recv_msg, BUFFER_SIZE); 

			 //std::lock_guard<std::mutex> lguard(my_mutex);
                         byte_num = recv(client_fds[i], recv_msg, BUFFER_SIZE, 0);    
                        if (byte_num > 0)    
                        {    
                            if(byte_num > (BUFFER_SIZE-4))    
                            {    
                                byte_num = (BUFFER_SIZE-4);    
                            }
                            recv_msg[byte_num++] = 'E';
                            recv_msg[byte_num++] = 'N';
                            recv_msg[byte_num++] = 'D';//添加消息的结尾标志
                            recv_msg[byte_num] = '\0';    
                            printf("RSU(%d):%s\n", i, recv_msg);    
                        }else if(byte_num < 0)    
                        {    
                            printf("从RSU(%d)接受消息出错.\n", i);    
                        } else    
                        {    
                            FD_CLR(client_fds[i], &server_fd_set);    
                            client_fds[i] = 0;    
                            printf("RSU客户端(%d)退出了\n", i);    
                        }    
                    }    
                }    
            }    
        }    
    }    
	return 0;
	
		
}	
//mqtt code -----------------------------------------------------



void connlost(void *context, char *cause)
{
	MQTTAsync client = (MQTTAsync)context;
	MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
	int rc;

	printf("\nConnection lost\n");
	printf("     cause: %s\n", cause);

	printf("Reconnecting\n");
	conn_opts.keepAliveInterval = 20;
	conn_opts.cleansession = 1;
	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start connect, return code %d\n", rc);
 		finished = 1;
	}
}


void onDisconnect(void* context, MQTTAsync_successData* response)
{
	printf("Successful disconnection\n");
	finished = 1;
}


void onSend(void* context, MQTTAsync_successData* response)
{
	//MQTTAsync client = (MQTTAsync)context;
	//MQTTAsync_disconnectOptions opts = MQTTAsync_disconnectOptions_initializer;
	//int rc;

	printf("Message with token value %d delivery confirmed\n", response->token);
      
	//opts.onSuccess = onDisconnect;
	//opts.context = client;
        /* 
	if ((rc = MQTTAsync_disconnect(client, &opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start sendMessage, return code %d\n", rc);
		exit(EXIT_FAILURE);
	}
          */
}


void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
	printf("Connect broker failed, rc %d\n", response ? response->code : 0);
	finished = 1;
}


void onConnect(void* context, MQTTAsync_successData* response)
{
	MQTTAsync client = (MQTTAsync)context;
	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
	MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
	int rc;

	printf("Successful connection\n");
	is_connect = true;
/*	opts.onSuccess = onSend;
	opts.context = client;

	pubmsg.payload = (void*)PAYLOAD;
	pubmsg.payloadlen = (int)strlen(PAYLOAD);
	pubmsg.qos = QOS;
	pubmsg.retained = 0;
	deliveredtoken = 0;
        
	    if ((rc = MQTTAsync_sendMessage(client, TOPIC, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
	    {
		printf("Failed to start sendMessage, return code %d\n", rc);
		exit(EXIT_FAILURE);
	    }
*/        
}




int wuxi_server()
{    
	std::mutex mqtt_mutex;
	MQTTAsync client;
	MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
	int rc;
        char test_msg[100]="RSU client message is not arrived.This is the test information, please ignore it.";
	MQTTAsync_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);

	MQTTAsync_setCallbacks(client, NULL, connlost, NULL, NULL);

	conn_opts.keepAliveInterval = 20;
	conn_opts.cleansession = 1;
	conn_opts.onSuccess = onConnect;
	conn_opts.onFailure = onConnectFailure;
	conn_opts.context = client;
        
	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start connect, return code %d\n", rc);
		exit(EXIT_FAILURE);
	}       
	printf("Waiting for publication of %s\n"
         "on topic %s for client with ClientID: %s\n",
         recv_msg, TOPIC, CLIENTID);
        while(!is_connect)
	{
	   //printf("sleep\n");
           usleep(100000L);
	}
        
	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;  
        opts.onSuccess = onSend;
	opts.context = client;
        
        while(1)
	{	   
	   int rc;
           //printf("while1\n");
           //#define MQTTAsync_message_initializer 
	   MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
	   //pubmsg.payload = (void*)PAYLOAD;
           
	   
           if(byte_num > 2)
           {        
               pubmsg.payload = (void*)recv_msg;
               pubmsg.payloadlen = (int)strlen(recv_msg);
           }else{
               pubmsg.payload = (void*)test_msg;
               pubmsg.payloadlen = (int)strlen(test_msg);
               usleep(2000000L); //(1ms = 1000us)  Send 1 times 2 second
           }

	   pubmsg.qos = QOS;
	   pubmsg.retained = 0;
	   deliveredtoken = 0;
           
	   if ((rc = MQTTAsync_sendMessage(client, TOPIC, &pubmsg, &opts)) != MQTTASYNC_SUCCESS)
	   {
		   printf("Failed to start sendMessage, return code %d\n", rc);
		   exit(EXIT_FAILURE);
	   }
	   std::lock_guard<std::mutex> lguard(mqtt_mutex);
	   memset(recv_msg,0,sizeof(recv_msg));
           byte_num = 0; 
	   //usleep(20000L);//Send 50 times a second
           usleep(100000L);
	}

	while (!finished)
		#if defined(WIN32)
			Sleep(100);
		#else
			usleep(10000L);
		#endif

	MQTTAsync_destroy(&client);
 	return rc;
	
		
	
}


   
int main(int argc, const char * argv[])    
{    
    std::thread th1(rsu_server);

    std::thread th2(wuxi_server);

    th1.detach();

    th2.detach();

    while(1)
    {
       #if defined(WIN32)
		Sleep(100);
       #else
		usleep(1000000L);
       #endif
    }    
    
    return 0;    
}   

MQTT subscruib.cpp代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTAsync.h"
#include <unistd.h>


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

volatile MQTTAsync_token deliveredtoken;

int disc_finished = 0;
int subscribed = 0;
int finished = 0;

void connlost(void *context, char *cause)
{
	MQTTAsync client = (MQTTAsync)context;
	MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
	int rc;

	printf("\nConnection lost\n");
	if (cause)
		printf("     cause: %s\n", cause);

	printf("Reconnecting\n");
	conn_opts.keepAliveInterval = 20;
	conn_opts.cleansession = 1;
	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start connect, return code %d\n", rc);
		finished = 1;
	}
}


int msgarrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message)
{
    int i;
    char* payloadptr;

    printf("Message arrived\n");
    printf("     topic: %s\n", topicName);
    printf("   message: ");

    payloadptr = (char*)message->payload;
    for(i=0; i<message->payloadlen; i++)
    {
        putchar(*payloadptr++);
    }
    putchar('\n');
    MQTTAsync_freeMessage(&message);
    MQTTAsync_free(topicName);
    return 1;
}


void onDisconnect(void* context, MQTTAsync_successData* response)
{
	printf("Successful disconnection\n");
	disc_finished = 1;
}


void onSubscribe(void* context, MQTTAsync_successData* response)
{
	printf("Subscribe succeeded\n");
	subscribed = 1;
}

void onSubscribeFailure(void* context, MQTTAsync_failureData* response)
{
	printf("Subscribe failed, rc %d\n", response ? response->code : 0);
	finished = 1;
}


void onConnectFailure(void* context, MQTTAsync_failureData* response)
{
	printf("Connect failed, rc %d\n", response ? response->code : 0);
	finished = 1;
}


void onConnect(void* context, MQTTAsync_successData* response)
{
	MQTTAsync client = (MQTTAsync)context;
	MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer;
	int rc;

	printf("Successful connection\n");

	printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
           "Press Q<Enter> to quit\n\n", TOPIC, CLIENTID, QOS);
	opts.onSuccess = onSubscribe;
	opts.onFailure = onSubscribeFailure;
	opts.context = client;

	deliveredtoken = 0;

	if ((rc = MQTTAsync_subscribe(client, TOPIC, QOS, &opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start subscribe, return code %d\n", rc);
		exit(EXIT_FAILURE);
	}
}


int main(int argc, char* argv[])
{
	MQTTAsync client;
	MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer;
	MQTTAsync_disconnectOptions disc_opts = MQTTAsync_disconnectOptions_initializer;
	int rc;
	int ch;

	MQTTAsync_create(&client, ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL);

	MQTTAsync_setCallbacks(client, client, connlost, msgarrvd, NULL);

	conn_opts.keepAliveInterval = 20;
	conn_opts.cleansession = 1;
	conn_opts.onSuccess = onConnect;
	conn_opts.onFailure = onConnectFailure;
	conn_opts.context = client;
	if ((rc = MQTTAsync_connect(client, &conn_opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start connect, return code %d\n", rc);
		exit(EXIT_FAILURE);
	}

	while	(!subscribed)
		#if defined(WIN32)
			Sleep(100);
		#else
			usleep(10000L);
		#endif

	if (finished)
		goto exit;

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

	disc_opts.onSuccess = onDisconnect;
	if ((rc = MQTTAsync_disconnect(client, &disc_opts)) != MQTTASYNC_SUCCESS)
	{
		printf("Failed to start disconnect, return code %d\n", rc);
		exit(EXIT_FAILURE);
	}
 	while	(!disc_finished)
		#if defined(WIN32)
			Sleep(100);
		#else
			usleep(10000L);
		#endif

exit:
	MQTTAsync_destroy(&client);
 	return rc;
}

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aFakeProgramer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值