MQTT_DEMO

    1. /* 
    2.   2 Copyright (c) 2009-2012 Roger Light <roger@atchoo.org> 
    3.   3 All rights reserved. 
    4.   4  
    5.   5 Redistribution and use in source and binary forms, with or without 
    6.   6 modification, are permitted provided that the following conditions are met: 
    7.   7  
    8.   8 1. Redistributions of source code must retain the above copyright notice, 
    9.   9    this list of conditions and the following disclaimer. 
    10.  10 2. Redistributions in binary form must reproduce the above copyright 
    11.  11    notice, this list of conditions and the following disclaimer in the 
    12.  12    documentation and/or other materials provided with the distribution. 
    13.  13 3. Neither the name of mosquitto nor the names of its 
    14.  14    contributors may be used to endorse or promote products derived from 
    15.  15    this software without specific prior written permission. 
    16.  16  
    17.  17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
    18.  18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
    19.  19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
    20.  20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
    21.  21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
    22.  22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
    23.  23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
    24.  24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
    25.  25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
    26.  26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
    27.  27 POSSIBILITY OF SUCH DAMAGE. 
    28.  28 */  
    29.  29   
    30.  30   
    31.  31 #include <errno.h>  
    32.  32 #include <fcntl.h>  
    33.  33 #include <stdio.h>  
    34.  34 #include <stdlib.h>  
    35.  35 #include <string.h>  
    36.  36 #ifndef WIN32  
    37.  37 #include <unistd.h>  
    38.  38 #else  
    39.  39 #include <process.h>  
    40.  40 #include <winsock2.h>  
    41.  41 #define snprintf sprintf_s  
    42.  42 #endif  
    43.  43   
    44.  44 #include <mosquitto.h>  
    45.  45   
    46.  46 #define MSGMODE_NONE 0  
    47.  47 #define MSGMODE_CMD 1  
    48.  48 #define MSGMODE_STDIN_LINE 2  
    49.  49 #define MSGMODE_STDIN_FILE 3  
    50.  50 #define MSGMODE_FILE 4  
    51.  51 #define MSGMODE_NULL 5  
    52.  52   
    53.  53 #define STATUS_CONNECTING 0  
    54.  54 #define STATUS_CONNACK_RECVD 1  
    55.  55   
    56.  56 static char *topic = NULL;  
    57.  57 static char *message = NULL;  
    58.  58 static long msglen = 0;  
    59.  59 static int qos = 0;  
    60.  60 static int retain = 0;  
    61.  61 static int mode = MSGMODE_NONE;        //消息类型,默认是MSGMODE_NONE  
    62.  62 static int status = STATUS_CONNECTING;  
    63.  63 static uint16_t mid_sent = 0;  
    64.  64 static bool connected = true;  
    65.  65 static char *username = NULL;  
    66.  66 static char *password = NULL;  
    67.  67 static bool disconnect_sent = false;  
    68.  68 static bool quiet = false;  
    69.  69   
    70.  70 void my_connect_callback(void *obj, int result)    //obj:<mosquitto_new>中提供的用户数据;result:0-成功,1-不可接受的协议版本,2-标示符拒绝,3-broker不可达。。。  
    71.  71 {  
    72.  72     //mode是MSGMODE_STDIN_FILE和MSGMODE_NULL时发布消息  
    73.  73     struct mosquitto *mosq = obj;  
    74.  74     int rc = MOSQ_ERR_SUCCESS;  
    75.  75   
    76.  76     if(!result){  
    77.  77         switch(mode){  
    78.  78             case MSGMODE_CMD:    //-m  
    79.  79             case MSGMODE_FILE:    //-f  
    80.  80             case MSGMODE_STDIN_FILE:    //-s  
    81.  81                 rc = mosquitto_publish(mosq, &mid_sent, topic, msglen, (uint8_t *)message, qos, retain);  
    82.  82                 break;  
    83.  83             case MSGMODE_NULL:    //-n  
    84.  84                 rc = mosquitto_publish(mosq, &mid_sent, topic, 0, NULL, qos, retain);  
    85.  85                 break;  
    86.  86             case MSGMODE_STDIN_LINE:    //-l  
    87.  87                 status = STATUS_CONNACK_RECVD;  
    88.  88                 break;  
    89.  89         }  
    90.  90         if(rc){  
    91.  91             if(!quiet){  
    92.  92                 switch(rc){  
    93.  93                     case MOSQ_ERR_INVAL:  
    94.  94                         fprintf(stderr, "Error: Invalid input. Does your topic contain '+' or '#'?\n");  
    95.  95                         break;  
    96.  96                     case MOSQ_ERR_NOMEM:  
    97.  97                         fprintf(stderr, "Error: Out of memory when trying to publish message.\n");  
    98.  98                         break;  
    99.  99                     case MOSQ_ERR_NO_CONN:  
    100. 100                         fprintf(stderr, "Error: Client not connected when trying to publish.\n");  
    101. 101                         break;  
    102. 102                     case MOSQ_ERR_PROTOCOL:  
    103. 103                         fprintf(stderr, "Error: Protocol error when communicating with broker.\n");  
    104. 104                         break;  
    105. 105                     case MOSQ_ERR_PAYLOAD_SIZE:  
    106. 106                         fprintf(stderr, "Error: Message payload is too large.\n");  
    107. 107                         break;  
    108. 108                 }  
    109. 109             }  
    110. 110             mosquitto_disconnect(mosq);  
    111. 111         }  
    112. 112     }else{  
    113. 113         switch(result){  
    114. 114             case 1:  
    115. 115                 if(!quiet) fprintf(stderr, "Connection Refused: unacceptable protocol version\n");  
    116. 116                 break;  
    117. 117             case 2:  
    118. 118                 if(!quiet) fprintf(stderr, "Connection Refused: identifier rejected\n");  
    119. 119                 break;  
    120. 120             case 3:  
    121. 121                 if(!quiet) fprintf(stderr, "Connection Refused: broker unavailable\n");  
    122. 122                 break;  
    123. 123             case 4:  
    124. 124                 if(!quiet) fprintf(stderr, "Connection Refused: bad user name or password\n");  
    125. 125                 break;  
    126. 126             case 5:  
    127. 127                 if(!quiet) fprintf(stderr, "Connection Refused: not authorised\n");  
    128. 128                 break;  
    129. 129             default:  
    130. 130                 if(!quiet) fprintf(stderr, "Connection Refused: unknown reason\n");  
    131. 131                 break;  
    132. 132         }  
    133. 133     }  
    134. 134 }  
    135. 135   
    136. 136 void my_disconnect_callback(void *obj)      
    137. 137 {  
    138. 138     //连接状态conneted设为false  
    139. 139     connected = false;  
    140. 140 }  
    141. 141   
    142. 142 void my_publish_callback(void *obj, uint16_t mid)          
    143. 143 {  
    144. 144     //mode不是MSGMODE_STDIN_LINE(-l,从标准输入读取消息)且disconnect_sent是false(未断开连接)时,与broker断开连接  
    145. 145     struct mosquitto *mosq = obj;  
    146. 146   
    147. 147     if(mode != MSGMODE_STDIN_LINE && disconnect_sent == false){  
    148. 148         mosquitto_disconnect(mosq);  
    149. 149         disconnect_sent = true;  
    150. 150     }  
    151. 151 }  
    152. 152   
    153. 153 int load_stdin(void)  
    154. 154 {  
    155. 155     //-s,从标准输入按文件读取,复制到message,直到遇到文件终止符EOF(ctrl+D)  
    156. 156     long pos = 0, rlen;  
    157. 157     char buf[1024];  
    158. 158   
    159. 159     mode = MSGMODE_STDIN_FILE;  
    160. 160   
    161. 161     while(!feof(stdin)){          
    162. 162         rlen = fread(buf, 1, 1024, stdin);  
    163. 163         message = realloc(message, pos+rlen);  
    164. 164         if(!message){  
    165. 165             if(!quiet) fprintf(stderr, "Error: Out of memory.\n");  
    166. 166             return 1;  
    167. 167         }  
    168. 168         memcpy(&(message[pos]), buf, rlen);  
    169. 169         pos += rlen;  
    170. 170     }  
    171. 171     msglen = pos;  
    172. 172   
    173. 173     if(!msglen){  
    174. 174         if(!quiet) fprintf(stderr, "Error: Zero length input.\n");  
    175. 175         return 1;  
    176. 176     }  
    177. 177   
    178. 178     return 0;  
    179. 179 }  
    180. 180   
    181. 181 int load_file(const char *filename)  
    182. 182 {  
    183. 183     long pos, rlen;  
    184. 184     FILE *fptr = NULL;  
    185. 185   
    186. 186     fptr = fopen(filename, "rb"); //只读打开一个二进制文件  
    187. 187     if(!fptr){  
    188. 188         if(!quiet) fprintf(stderr, "Error: Unable to open file \"%s\".\n", filename);  
    189. 189         return 1;  
    190. 190     }  
    191. 191     mode = MSGMODE_FILE;  
    192. 192     fseek(fptr, 0, SEEK_END);  
    193. 193     msglen = ftell(fptr);    //获取文件当前读写位置偏移字节数,即文本长度  
    194. 194     if(msglen > 268435455){    //不超过255MB  
    195. 195         fclose(fptr);  
    196. 196         if(!quiet) fprintf(stderr, "Error: File \"%s\" is too large (>268,435,455 bytes).\n", filename);  
    197. 197         return 1;  
    198. 198     }  
    199. 199     if(msglen == 0){  
    200. 200         fclose(fptr);  
    201. 201         if(!quiet) fprintf(stderr, "Error: File \"%s\" is empty.\n", filename);  
    202. 202         return 1;  
    203. 203     }  
    204. 204     fseek(fptr, 0, SEEK_SET);  
    205. 205     message = malloc(msglen);  
    206. 206     if(!message){  
    207. 207         fclose(fptr);  
    208. 208         if(!quiet) fprintf(stderr, "Error: Out of memory.\n");  
    209. 209         return 1;  
    210. 210     }  
    211. 211     pos = 0;  
    212. 212     //读取文件内容至message中  
    213. 213     while(pos < msglen){  
    214. 214         rlen = fread(&(message[pos]), sizeof(char), msglen-pos, fptr);  
    215. 215         pos += rlen;  
    216. 216     }  
    217. 217     fclose(fptr);  
    218. 218     return 0;  
    219. 219 }  
    220. 220   
    221. 221 void print_usage(void)  
    222. 222 {  
    223. 223     printf("mosquitto_pub is a simple mqtt client that will publish a message on a single topic and exit.\n\n");  
    224. 224     printf("Usage: mosquitto_pub [-h host] [-p port] [-q qos] [-r] {-f file | -l | -n | -m message} -t topic\n");  
    225. 225     printf("                     [-i id] [-I id_prefix]\n");  
    226. 226     printf("                     [-d] [--quiet]\n");  
    227. 227     printf("                     [-u username [-P password]]\n");  
    228. 228     printf("                     [--will-topic [--will-payload payload] [--will-qos qos] [--will-retain]]\n\n");  
    229. 229     printf(" -d : enable debug messages.\n");  
    230. 230     printf(" -f : send the contents of a file as the message.\n");  
    231. 231     printf(" -h : mqtt host to connect to. Defaults to localhost.\n");  
    232. 232     printf(" -i : id to use for this client. Defaults to mosquitto_pub_ appended with the process id.\n");  
    233. 233     printf(" -I : define the client id as id_prefix appended with the process id. Useful for when the\n");  
    234. 234     printf("      broker is using the clientid_prefixes option.\n");  
    235. 235     printf(" -l : read messages from stdin, sending a separate message for each line.\n");  
    236. 236     printf(" -m : message payload to send.\n");  
    237. 237     printf(" -n : send a null (zero length) message.\n");  
    238. 238     printf(" -p : network port to connect to. Defaults to 1883.\n");  
    239. 239     printf(" -q : quality of service level to use for all messages. Defaults to 0.\n");  
    240. 240     printf(" -r : message should be retained.\n");  
    241. 241     printf(" -s : read message from stdin, sending the entire input as a message.\n");  
    242. 242     printf(" -t : mqtt topic to publish to.\n");  
    243. 243     printf(" -u : provide a username (requires MQTT 3.1 broker)\n");  
    244. 244     printf(" -P : provide a password (requires MQTT 3.1 broker)\n");  
    245. 245     printf(" --quiet : don't print error messages.\n");  
    246. 246     printf(" --will-payload : payload for the client Will, which is sent by the broker in case of\n");  
    247. 247     printf("                  unexpected disconnection. If not given and will-topic is set, a zero\n");  
    248. 248     printf("                  length message will be sent.\n");  
    249. 249     printf(" --will-qos : QoS level for the client Will.\n");  
    250. 250     printf(" --will-retain : if given, make the client Will retained.\n");  
    251. 251     printf(" --will-topic : the topic on which to publish the client Will.\n");  
    252. 252     printf("\nSee http://mosquitto.org/ for more information.\n\n");  
    253. 253 }  
    254. 254   
    255. 255 int main(int argc, char *argv[])  
    256. 256 {  
    257. 257     char *id = NULL;    //client ID  
    258. 258     char *id_prefix = NULL;    //client ID 前缀  
    259. 259     int i;  
    260. 260     char *host = "localhost";    //server IP,默认是localhost  
    261. 261     int port = 1883;    //server PORT,默认是1883  
    262. 262     int keepalive = 60;        //  
    263. 263     int opt;  
    264. 264     char buf[1024];  
    265. 265     bool debug = false;        //是否打印debug消息  
    266. 266     struct mosquitto *mosq = NULL;  
    267. 267     int rc;  
    268. 268     int rc2;  
    269. 269     char hostname[21];  
    270. 270     char err[1024];  
    271. 271   
    272. 272     uint8_t *will_payload = NULL;  
    273. 273     long will_payloadlen = 0;  
    274. 274     int will_qos = 0;  
    275. 275     bool will_retain = false;  
    276. 276     char *will_topic = NULL;  
    277. 277   
    278. 278     //获取命令参数  
    279. 279     for(i=1; i<argc; i++){  
    280. 280         if(!strcmp(argv[i], "-p") || !strcmp(argv[i], "--port")){    //端口号  
    281. 281             if(i==argc-1){  
    282. 282                 fprintf(stderr, "Error: -p argument given but no port specified.\n\n");  
    283. 283                 print_usage();  
    284. 284                 return 1;  
    285. 285             }else{  
    286. 286                 port = atoi(argv[i+1]);  
    287. 287                 if(port<1 || port>65535){  
    288. 288                     fprintf(stderr, "Error: Invalid port given: %d\n", port);  
    289. 289                     print_usage();  
    290. 290                     return 1;  
    291. 291                 }  
    292. 292             }  
    293. 293             i++;  
    294. 294         }else if(!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")){    //debug选项  
    295. 295             debug = true;  
    296. 296         }else if(!strcmp(argv[i], "-f") || !strcmp(argv[i], "--file")){        //-f,读取文件  
    297. 297             if(mode != MSGMODE_NONE){  
    298. 298                 fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");  
    299. 299                 print_usage();  
    300. 300                 return 1;  
    301. 301             }else if(i==argc-1){  
    302. 302                 fprintf(stderr, "Error: -f argument given but no file specified.\n\n");  
    303. 303                 print_usage();  
    304. 304                 return 1;  
    305. 305             }else{  
    306. 306                 if(load_file(argv[i+1])) return 1;  
    307. 307             }  
    308. 308             i++;  
    309. 309         }else if(!strcmp(argv[i], "-h") || !strcmp(argv[i], "--host")){        //-h,server IP  
    310. 310             if(i==argc-1){  
    311. 311                 fprintf(stderr, "Error: -h argument given but no host specified.\n\n");  
    312. 312                 print_usage();  
    313. 313                 return 1;  
    314. 314             }else{  
    315. 315                 host = argv[i+1];  
    316. 316             }  
    317. 317             i++;  
    318. 318         }else if(!strcmp(argv[i], "-i") || !strcmp(argv[i], "--id")){        //-i, client id  
    319. 319             if(id_prefix){  
    320. 320                 fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n");  
    321. 321                 print_usage();  
    322. 322                 return 1;  
    323. 323             }  
    324. 324             if(i==argc-1){  
    325. 325                 fprintf(stderr, "Error: -i argument given but no id specified.\n\n");  
    326. 326                 print_usage();  
    327. 327                 return 1;  
    328. 328             }else{  
    329. 329                 id = argv[i+1];  
    330. 330             }  
    331. 331             i++;  
    332. 332         }else if(!strcmp(argv[i], "-I") || !strcmp(argv[i], "--id-prefix")){     //-I,client id前缀  
    333. 333             if(id){  
    334. 334                 fprintf(stderr, "Error: -i and -I argument cannot be used together.\n\n");  
    335. 335                 print_usage();  
    336. 336                 return 1;  
    337. 337             }  
    338. 338             if(i==argc-1){  
    339. 339                 fprintf(stderr, "Error: -I argument given but no id prefix specified.\n\n");  
    340. 340                 print_usage();  
    341. 341                 return 1;  
    342. 342             }else{  
    343. 343                 id_prefix = argv[i+1];  
    344. 344             }  
    345. 345             i++;  
    346. 346         }else if(!strcmp(argv[i], "-l") || !strcmp(argv[i], "--stdin-line")){        //-l,从标准输入按行读取发送消息,一行发送一条消息  
    347. 347             if(mode != MSGMODE_NONE){  
    348. 348                 fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");  
    349. 349                 print_usage();  
    350. 350                 return 1;  
    351. 351             }else{  
    352. 352                 mode = MSGMODE_STDIN_LINE;  
    353. 353 #ifndef WIN32  
    354. 354                 opt = fcntl(fileno(stdin), F_GETFL, 0); //获取文件的flags  
    355. 355                 if(opt == -1 || fcntl(fileno(stdin), F_SETFL, opt | O_NONBLOCK) == -1){ //设置文件flags非阻塞O_NONBLOCK  
    356. 356                     fprintf(stderr, "Error: Unable to set stdin to non-blocking.\n");  
    357. 357                     return 1;  
    358. 358                 }  
    359. 359 #endif  
    360. 360             }  
    361. 361         }else if(!strcmp(argv[i], "-m") || !strcmp(argv[i], "--message")){    //-m,从cmd发送消息,消息内容跟在-m之后  
    362. 362             if(mode != MSGMODE_NONE){  
    363. 363                 fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");  
    364. 364                 print_usage();  
    365. 365                 return 1;  
    366. 366             }else if(i==argc-1){  
    367. 367                 fprintf(stderr, "Error: -m argument given but no message specified.\n\n");  
    368. 368                 print_usage();  
    369. 369                 return 1;  
    370. 370             }else{  
    371. 371                 message = argv[i+1];  
    372. 372                 msglen = strlen(message);  
    373. 373                 mode = MSGMODE_CMD;  
    374. 374             }  
    375. 375             i++;  
    376. 376         }else if(!strcmp(argv[i], "-n") || !strcmp(argv[i], "--null-message")){        //-n,发送空消息  
    377. 377             if(mode != MSGMODE_NONE){  
    378. 378                 fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");  
    379. 379                 print_usage();  
    380. 380                 return 1;  
    381. 381             }else{  
    382. 382                 mode = MSGMODE_NULL;  
    383. 383             }  
    384. 384         }else if(!strcmp(argv[i], "-q") || !strcmp(argv[i], "--qos")){        //-q,服务质量,0,1,或2  
    385. 385             if(i==argc-1){  
    386. 386                 fprintf(stderr, "Error: -q argument given but no QoS specified.\n\n");  
    387. 387                 print_usage();  
    388. 388                 return 1;  
    389. 389             }else{  
    390. 390                 qos = atoi(argv[i+1]);  
    391. 391                 if(qos<0 || qos>2){  
    392. 392                     fprintf(stderr, "Error: Invalid QoS given: %d\n", qos);  
    393. 393                     print_usage();  
    394. 394                     return 1;  
    395. 395                 }  
    396. 396             }  
    397. 397             i++;  
    398. 398         }else if(!strcmp(argv[i], "--quiet")){    //-quiet,什么都不打印出来  
    399. 399             quiet = true;  
    400. 400         }else if(!strcmp(argv[i], "-r") || !strcmp(argv[i], "--retain")){    //-r,retained消息会在服务器上保留,但只保留带-r标志的最后一条消息  
    401. 401             retain = 1;  
    402. 402         }else if(!strcmp(argv[i], "-s") || !strcmp(argv[i], "--stdin-file")){        //-s,从标准输入按文件读取,到EOF时把所有输入内容用一条消息发送  
    403. 403             if(mode != MSGMODE_NONE){  
    404. 404                 fprintf(stderr, "Error: Only one type of message can be sent at once.\n\n");  
    405. 405                 print_usage();  
    406. 406                 return 1;  
    407. 407             }else{  
    408. 408                 if(load_stdin()) return 1;  
    409. 409             }  
    410. 410         }else if(!strcmp(argv[i], "-t") || !strcmp(argv[i], "--topic")){    //-t,消息主题,只能发布一个主题  
    411. 411             if(i==argc-1){      
    412. 412                 fprintf(stderr, "Error: -t argument given but no topic specified.\n\n");  
    413. 413                 print_usage();  
    414. 414                 return 1;  
    415. 415             }else{  
    416. 416                 topic = argv[i+1];  
    417. 417             }  
    418. 418             i++;  
    419. 419         }else if(!strcmp(argv[i], "-u") || !strcmp(argv[i], "--username")){        //-u,username  
    420. 420             if(i==argc-1){  
    421. 421                 fprintf(stderr, "Error: -u argument given but no username specified.\n\n");  
    422. 422                 print_usage();  
    423. 423                 return 1;  
    424. 424             }else{  
    425. 425                 username = argv[i+1];  
    426. 426             }  
    427. 427             i++;  
    428. 428         }else if(!strcmp(argv[i], "-P") || !strcmp(argv[i], "--pw")){    //-P,password  
    429. 429             if(i==argc-1){  
    430. 430                 fprintf(stderr, "Error: -P argument given but no password specified.\n\n");  
    431. 431                 print_usage();  
    432. 432                 return 1;  
    433. 433             }else{  
    434. 434                 password = argv[i+1];  
    435. 435             }  
    436. 436             i++;  
    437. 437         }else if(!strcmp(argv[i], "--will-payload")){  
    438. 438             if(i==argc-1){  
    439. 439                 fprintf(stderr, "Error: --will-payload argument given but no will payload specified.\n\n");  
    440. 440                 print_usage();  
    441. 441                 return 1;  
    442. 442             }else{  
    443. 443                 will_payload = (uint8_t *)argv[i+1];  
    444. 444                 will_payloadlen = strlen((char *)will_payload);  
    445. 445             }  
    446. 446             i++;  
    447. 447         }else if(!strcmp(argv[i], "--will-qos")){  
    448. 448             if(i==argc-1){  
    449. 449                 fprintf(stderr, "Error: --will-qos argument given but no will QoS specified.\n\n");  
    450. 450                 print_usage();  
    451. 451                 return 1;  
    452. 452             }else{  
    453. 453                 will_qos = atoi(argv[i+1]);  
    454. 454                 if(will_qos < 0 || will_qos > 2){  
    455. 455                     fprintf(stderr, "Error: Invalid will QoS %d.\n\n", will_qos);  
    456. 456                     return 1;  
    457. 457                 }  
    458. 458             }  
    459. 459             i++;  
    460. 460         }else if(!strcmp(argv[i], "--will-retain")){  
    461. 461             will_retain = true;  
    462. 462         }else if(!strcmp(argv[i], "--will-topic")){  
    463. 463             if(i==argc-1){  
    464. 464                 fprintf(stderr, "Error: --will-topic argument given but no will topic specified.\n\n");  
    465. 465                 print_usage();  
    466. 466                 return 1;  
    467. 467             }else{  
    468. 468                 will_topic = argv[i+1];  
    469. 469             }  
    470. 470             i++;  
    471. 471         }else{  
    472. 472             fprintf(stderr, "Error: Unknown option '%s'.\n",argv[i]);  
    473. 473             print_usage();  
    474. 474             return 1;  
    475. 475         }  
    476. 476     }  
    477. 477     if(id_prefix){    //有设定client ID前缀  
    478. 478         id = malloc(strlen(id_prefix)+10);  
    479. 479         if(!id){  
    480. 480             if(!quiet) fprintf(stderr, "Error: Out of memory.\n");  
    481. 481             return 1;  
    482. 482         }  
    483. 483         snprintf(id, strlen(id_prefix)+10, "%s%d", id_prefix, getpid());  
    484. 484     }else if(!id){        //没有前缀,也没有设定client ID  
    485. 485         id = malloc(30);  
    486. 486         if(!id){  
    487. 487             if(!quiet) fprintf(stderr, "Error: Out of memory.\n");  
    488. 488             return 1;  
    489. 489         }  
    490. 490         memset(hostname, 0, 21);  
    491. 491         gethostname(hostname, 20);    //获得主机名  
    492. 492         snprintf(id, 23, "mosq_pub_%d_%s", getpid(), hostname);  
    493. 493     }  
    494. 494   
    495. 495     if(!topic || mode == MSGMODE_NONE){  
    496. 496         fprintf(stderr, "Error: Both topic and message must be supplied.\n");  
    497. 497         print_usage();  
    498. 498         return 1;  
    499. 499     }  
    500. 500   
    501. 501     if(will_payload && !will_topic){  
    502. 502         fprintf(stderr, "Error: Will payload given, but no will topic given.\n");  
    503. 503         print_usage();  
    504. 504         return 1;  
    505. 505     }  
    506. 506     if(will_retain && !will_topic){  
    507. 507         fprintf(stderr, "Error: Will retain given, but no will topic given.\n");  
    508. 508         print_usage();  
    509. 509         return 1;  
    510. 510     }  
    511. 511     if(password && !username){  
    512. 512         if(!quiet) fprintf(stderr, "Warning: Not using password since username not set.\n");  
    513. 513     }  
    514. 514     mosquitto_lib_init();    //任何mosquitto functions之前都必须调用的函数,初始化操作  
    515. 515     mosq = mosquitto_new(id, NULL);    //新建一个 mosquitto client实例  
    516. 516     if(!mosq){        //未建成功client实例  
    517. 517         if(!quiet) fprintf(stderr, "Error: Out of memory.\n");  
    518. 518         return 1;  
    519. 519     }  
    520. 520     if(debug){        //需要记录debug信息,初始化  
    521. 521         mosquitto_log_init(mosq, MOSQ_LOG_DEBUG | MOSQ_LOG_ERR | MOSQ_LOG_WARNING  
    522. 522                 | MOSQ_LOG_NOTICE | MOSQ_LOG_INFO, MOSQ_LOG_STDERR);  
    523. 523     }  
    524. 524     if(will_topic && mosquitto_will_set(mosq, true, will_topic, will_payloadlen, will_payload, will_qos, will_retain)){        //will信息配置,在connect之前调用  
    525. 525         if(!quiet) fprintf(stderr, "Error: Problem setting will.\n");  
    526. 526         return 1;  
    527. 527     }  
    528. 528     if(username && mosquitto_username_pw_set(mosq, username, password)){        //设置用户名,密码  
    529. 529         if(!quiet) fprintf(stderr, "Error: Problem setting username and password.\n");  
    530. 530         return 1;  
    531. 531     }  
    532. 532   
    533. 533     mosquitto_connect_callback_set(mosq, my_connect_callback);    //设置当broker给一个连接回复CONNACK时所调用的函数void callback(void *obj, int rc)  
    534. 534     mosquitto_disconnect_callback_set(mosq, my_disconnect_callback);    //设置当broker收到DISCONNECT命令且与client断开后调用的函数  
    535. 535     mosquitto_publish_callback_set(mosq, my_publish_callback);        //设置当一条被<mosquitto_publish>初始化的消息发送给broker后调用的函数  
    536. 536   
    537. 537     rc = mosquitto_connect(mosq, host, port, keepalive, true);    //连接到一个MQTT broker  
    538. 538     if(rc){  
    539. 539         //连接不成功  
    540. 540         if(!quiet){  
    541. 541             if(rc == MOSQ_ERR_ERRNO){  
    542. 542 #ifndef WIN32  
    543. 543                 strerror_r(errno, err, 1024);  
    544. 544 #else  
    545. 545                 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, errno, 0, (LPTSTR)&err, 1024, NULL);  
    546. 546 #endif  
    547. 547                 fprintf(stderr, "Error: %s\n", err);  
    548. 548             }else{  
    549. 549                 fprintf(stderr, "Unable to connect (%d).\n", rc);  
    550. 550             }  
    551. 551         }  
    552. 552         return rc;  
    553. 553     }  
    554. 554   
    555. 555     do{  
    556. 556         if(mode == MSGMODE_STDIN_LINE && status == STATUS_CONNACK_RECVD){  
    557. 557             if(fgets(buf, 1024, stdin)){  
    558. 558                 buf[strlen(buf)-1] = '\0';  
    559. 559                 rc2 = mosquitto_publish(mosq, &mid_sent, topic, strlen(buf), (uint8_t *)buf, qos, retain);  
    560. 560                 if(rc2){  
    561. 561                     if(!quiet) fprintf(stderr, "Error: Publish returned %d, disconnecting.\n", rc2);  
    562. 562                     mosquitto_disconnect(mosq);  
    563. 563                 }  
    564. 564             }else if(feof(stdin) && disconnect_sent == false){  
    565. 565                 mosquitto_disconnect(mosq);  
    566. 566                 disconnect_sent = true;  
    567. 567             }  
    568. 568         }  
    569. 569         rc = mosquitto_loop(mosq, -1);  
    570. 570     }while(rc == MOSQ_ERR_SUCCESS && connected);  
    571. 571   
    572. 572     if(message && mode == MSGMODE_FILE){  
    573. 573         free(message);  
    574. 574     }  
    575. 575     mosquitto_destroy(mosq);        //释放mosquitto实例的内存空间  
    576. 576     mosquitto_lib_cleanup();        //释放library所使用的资源  
    577. 577     return rc;  
    578. 578 } 
posted @ 2017-06-08 16:33  丁培飞  阅读(417)  评论(0编辑  收藏  举报