1. 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 }

MQTT_DEMO的更多相关文章

  1. linux c MQTT客户端实现

    linux c MQTT客户端实现 摘自:https://www.jianshu.com/p/d309de966379 一.前言:mqtt协议是轻量级的消息订阅和发布(publish/subscrib ...

  2. 物联网消息队列协议MQTT

    简介Mqtt是一个物联网消息传输协议 mosquitto是mqtt协议的一个开源实现,http://mosquitto.org/ paho是mqtt协议的客户端实现,这里主要用paho的mqtt ja ...

随机推荐

  1. 《FPGA全程进阶---实战演练》第八章之程序架构格式说明

    首先在书写程序时必须有的部分,就是模块module部分,整体的架构如图8.1所示. 图8.1 程序整体架构 首先要声明模块名,在module后面加上模块名,这里最好以所建立模块要实现的功能去命名此模块 ...

  2. vb.net与c#相互转换工具

    vb.net与c#相互转换工具:  http://www.developerfusion.co.uk/utilities/convertvbtocsharp.aspx http://www.dotne ...

  3. C++编程基础练习

    注:本文练习题均出自<Essential C++>第一章 练习1,1 从一个简单程序开始 #include<iostream> #include<string> u ...

  4. python numpy logic_and

    >>> import numpy as np >>> np.logical_and(True, False) False >>> np.logic ...

  5. 架构 : 三层架构、MVC、MVP、MVVM

    1. 三层架构   将整个业务应用划分为:界面层(User Interface layer, UIL).业务逻辑层(Business Logic Layer, BLL).数据访问层(Data acce ...

  6. vegan 包进行Adonis 分析

    Adonis 分析 是基于距离矩阵的多变量方差置换分析, 代码示例: 默认使用bray 距离来计算样本间的距离矩阵 参考资料: https://www.rdocumentation.org/packa ...

  7. linux中service的问题

    1.描述问题 2.解决方案 systemctl stop firewalld systemctl mask firewalld Then, install the iptables-services ...

  8. git默认忽略文件的大小写

  9. .net framework 4.0 在 VS2010 安装目录下位置 dotNetFx40_Full_x86_x64.exe在磁盘哪个目录?

    .net framework 4.0 在 VS2010 安装目录下位置 dotNetFx40_Full_x86_x64.exe在磁盘哪个目录? 使用VS2010开发应用程序完毕后,在发布应用程序时,常 ...

  10. [转]jmeter 自定义测试脚本

    http://blog.csdn.net/kash_chen007/article/details/37690411 http://wangym.iteye.com/blog/731729 1.创建一 ...