├── README.md ├── for-redis-2.6 ├── README.md ├── SimpleRedisClient.cpp ├── SimpleRedisClient.h └── main.cpp └── for-redis-2.8 ├── README.md ├── SimpleRedisClient.cpp ├── SimpleRedisClient.h └── main.cpp /README.md: -------------------------------------------------------------------------------- 1 |

Клиент для работы с редисом

2 | 3 | 4 | This client tested only on Ubuntu, Debian, CentOS. (Этот клиент тестировался только под Ubuntu, Debian, CentOS) 5 | 6 | 7 |

В разных версиях redis имеются отличия в протоколе, чтоб не усложнять код и не плодить баги для каждой версии redis свой клинт.

8 | 9 |

Последние изменения

10 |

11 |

17 |

18 | 19 |

Пример использования

20 |
21 | int main(int argc, char *argv[])
22 | {
23 |     SimpleRedisClient rc;
24 |   
25 |     rc.setHost(REDIS_HOST);
26 |     rc.auth(REDIS_PW);
27 |     rc.LogLevel(0);
28 | 
29 |     if(!rc)
30 |     {
31 |         printf("Соединение с redis не установлено\n");
32 |         return -1;
33 |     }
34 |     
35 |     rc = "MYKEY my-value-tester";
36 |     if(rc["MYKEY"])
37 |     {
38 |         printf("MYKEY == [%d][%s]\n", (int)rc, (char*)rc);
39 |     }
40 |   
41 |     printf("-------------------\n");
42 |     rc.sadd_printf("%s %d", "MY_SET", 123);
43 |     rc.sadd_printf("%s %d", "MY_SET", 14);
44 | 
45 |     rc.smembers("MY_SET");
46 | 
47 |     if(rc.getMultiBulkDataAmount())
48 |     {
49 |         for(int i =0; i< rc.getMultiBulkDataAmount(); i++ )
50 |         {
51 |             printf("Answer[%d]->%s\n", i, rc.getData(i));
52 |         }
53 |     }
54 | 
55 |     rc = "MYKEY1 my-value-tester";
56 |     rc = "MYKEY2 my-value-tester";
57 | 
58 |     rc.delete_keys("MY*");
59 |      
60 |     rc.redis_close();
61 | }
62 | 
-------------------------------------------------------------------------------- /for-redis-2.6/README.md: -------------------------------------------------------------------------------- 1 |

Клиент для работы с редисом версии 2.6

2 | 3 | 4 | This client tested only on Ubuntu, Debian, CentOS. (Этот клиент тестировался только под Ubuntu, Debian, CentOS) 5 | 6 | 7 |

Тестировался для redis версии 2.6

8 |

В разных версиях redis имеются отличия в протоколе, чтоб не усложнять код и не плодить баги для каждой версии redis свой клинт.

9 | 10 |

Последние изменения

11 |

12 |

17 |

18 | 19 |
20 | int main(int argc, char *argv[])
21 | {
22 |     SimpleRedisClient rc;
23 |   
24 |     rc.setHost(REDIS_HOST);
25 |     rc.auth(REDIS_PW);
26 |     rc.LogLevel(0);
27 | 
28 |     if(!rc)
29 |     {
30 |         printf("Соединение с redis не установлено\n");
31 |         return -1;
32 |     }
33 |     
34 |     rc = "MYKEY my-value-tester";
35 |     if(rc["MYKEY"])
36 |     {
37 |         printf("MYKEY == [%d][%s]\n", (int)rc, (char*)rc);
38 |     }
39 |   
40 |     printf("-------------------\n");
41 |     rc.sadd_printf("%s %d", "MY_SET", 123);
42 |     rc.sadd_printf("%s %d", "MY_SET", 14);
43 | 
44 |     rc.smembers("MY_SET");
45 | 
46 |     if(rc.getMultiBulkDataAmount())
47 |     {
48 |         for(int i =0; i< rc.getMultiBulkDataAmount(); i++ )
49 |         {
50 |             printf("Answer[%d]->%s\n", i, rc.getData(i));
51 |         }
52 |     }
53 | 
54 |     rc = "MYKEY1 my-value-tester";
55 |     rc = "MYKEY2 my-value-tester";
56 | 
57 |     rc.delete_keys("MY*");
58 |      
59 |     rc.redis_close();
60 | }
61 | 
62 | 63 | -------------------------------------------------------------------------------- /for-redis-2.6/SimpleRedisClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SimpleRedisClient.cpp 3 | * Author: victor 4 | * 5 | * Created on 10 Август 2013 г., 22:26 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include "backtrace.h" 37 | 38 | #include "SimpleRedisClient.h" 39 | 40 | #define debugLine printf("\n%s:%d\n", __FILE__, __LINE__) 41 | 42 | /** 43 | * Читает целое число из строки, если ошибка то вернёт -1 44 | * @param buffer Строка 45 | * @param delimiter Конец для числа 46 | * @param delta Количество символов занятое числом и разделителем 47 | * @return 48 | */ 49 | int read_int(const char* buffer,char delimiter,int* delta) 50 | { 51 | const char* p = buffer; 52 | int len = 0; 53 | int d = 0; 54 | 55 | while(*p == '0' ) 56 | { 57 | (*delta)++; 58 | p++; 59 | //return 0; 60 | } 61 | 62 | while(*p != delimiter) 63 | { 64 | if(*p > '9' || *p < '0') 65 | { 66 | return -1; 67 | } 68 | 69 | len = (len*10)+(*p - '0'); 70 | p++; 71 | (*delta)++; 72 | d++; 73 | 74 | if(d > 9) 75 | { 76 | return -1; 77 | } 78 | } 79 | return len; 80 | } 81 | 82 | int read_int(const char* buffer,char delimiter) 83 | { 84 | const char* p = buffer; 85 | int len = 0; 86 | int delta = 0; 87 | 88 | while(*p == '0' ) 89 | { 90 | p++; 91 | } 92 | 93 | while(*p != delimiter) 94 | { 95 | if(*p > '9' || *p < '0') 96 | { 97 | return -1; 98 | } 99 | 100 | len = (len*10)+(*p - '0'); 101 | p++; 102 | delta++; 103 | if(delta > 9) 104 | { 105 | return -1; 106 | } 107 | } 108 | 109 | return len; 110 | } 111 | 112 | int read_int(const char* buffer, int* delta) 113 | { 114 | const char* p = buffer; 115 | int len = 0; 116 | int d = 0; 117 | 118 | while(*p == '0' ) 119 | { 120 | (*delta)++; 121 | p++; 122 | //return 0; 123 | } 124 | 125 | while(1) 126 | { 127 | if(*p > '9' || *p < '0') 128 | { 129 | return len; 130 | } 131 | 132 | len = (len*10)+(*p - '0'); 133 | p++; 134 | (*delta)++; 135 | d++; 136 | 137 | if(d > 9) 138 | { 139 | return -1; 140 | } 141 | } 142 | return len; 143 | } 144 | /** 145 | * Читает целое число из строки, если ошибка то вернёт -1 146 | * @param buffer Строка 147 | * @param delimiter Конец для числа 148 | * @param delta Количество символов занятое числом и разделителем 149 | * @return 150 | */ 151 | long read_long(const char* buffer,char delimiter,int* delta) 152 | { 153 | const char* p = buffer; 154 | int len = 0; 155 | int d = 0; 156 | 157 | while(*p == '0' ) 158 | { 159 | (*delta)++; 160 | p++; 161 | //return 0; 162 | } 163 | 164 | while(*p != delimiter) 165 | { 166 | if(*p > '9' || *p < '0') 167 | { 168 | return -1; 169 | } 170 | 171 | len = (len*10)+(*p - '0'); 172 | p++; 173 | (*delta)++; 174 | d++; 175 | 176 | if(d > 18) 177 | { 178 | return -1; 179 | } 180 | } 181 | return len; 182 | } 183 | 184 | long read_long(const char* buffer,char delimiter) 185 | { 186 | const char* p = buffer; 187 | int len = 0; 188 | int delta = 0; 189 | 190 | while(*p == '0' ) 191 | { 192 | p++; 193 | } 194 | 195 | while(*p != delimiter) 196 | { 197 | if(*p > '9' || *p < '0') 198 | { 199 | return -1; 200 | } 201 | 202 | len = (len*10)+(*p - '0'); 203 | p++; 204 | delta++; 205 | if(delta > 18) 206 | { 207 | return -1; 208 | } 209 | } 210 | 211 | return len; 212 | } 213 | 214 | long read_long(const char* buffer, int* delta) 215 | { 216 | const char* p = buffer; 217 | int len = 0; 218 | int d = 0; 219 | 220 | while(*p == '0' ) 221 | { 222 | (*delta)++; 223 | p++; 224 | //return 0; 225 | } 226 | 227 | while(1) 228 | { 229 | if(*p > '9' || *p < '0') 230 | { 231 | return len; 232 | } 233 | 234 | len = (len*10)+(*p - '0'); 235 | p++; 236 | (*delta)++; 237 | d++; 238 | 239 | if(d > 18) 240 | { 241 | return -1; 242 | } 243 | } 244 | return len; 245 | } 246 | 247 | #define REDIS_PRINTF_MACRO_CODE(type, comand) va_list ap;\ 248 | va_start(ap, format);\ 249 | bzero(buf, buffer_size);\ 250 | int rc = vsnprintf(buf, buffer_size, format, ap);\ 251 | va_end(ap);\ 252 | if( rc >= buffer_size ) return RC_ERR_BUFFER_OVERFLOW;\ 253 | if(rc < 0) return RC_ERR_DATA_FORMAT;\ 254 | rc = redis_send( type, "%s %s\r\n", comand, buf);\ 255 | return rc;\ 256 | 257 | 258 | SimpleRedisClient::SimpleRedisClient() 259 | { 260 | setBufferSize(2048); 261 | } 262 | 263 | int SimpleRedisClient::getBufferSize() 264 | { 265 | return buffer_size; 266 | } 267 | 268 | 269 | void SimpleRedisClient::setMaxBufferSize(int size) 270 | { 271 | max_buffer_size = size; 272 | } 273 | 274 | int SimpleRedisClient::getMaxBufferSize() 275 | { 276 | return max_buffer_size; 277 | } 278 | 279 | void SimpleRedisClient::setBufferSize(int size) 280 | { 281 | if(buffer != 0) 282 | { 283 | delete[] buffer; 284 | delete[] buf; 285 | } 286 | 287 | buffer_size = size; 288 | buffer = new char[buffer_size]; 289 | buf = new char[buffer_size]; 290 | } 291 | 292 | SimpleRedisClient::~SimpleRedisClient() 293 | { 294 | redis_close(); 295 | 296 | 297 | if(buffer != NULL) 298 | { 299 | delete[] buffer; 300 | } 301 | 302 | if(buf != NULL) 303 | { 304 | delete[] buf; 305 | } 306 | 307 | buffer_size = 0; 308 | 309 | if(host != 0) 310 | { 311 | delete[] host; 312 | } 313 | 314 | if(lastAuthPw != NULL) 315 | { 316 | delete[] lastAuthPw; 317 | } 318 | } 319 | 320 | /* 321 | * Returns: 322 | * >0 Колво байт 323 | * 0 Соединение закрыто 324 | * -1 error 325 | * -2 timeout 326 | **/ 327 | int SimpleRedisClient::read_select(int fd, int timeout ) const 328 | { 329 | struct timeval tv; 330 | fd_set fds; 331 | 332 | tv.tv_sec = timeout / 1000; 333 | tv.tv_usec = (timeout % 1000)*1000; 334 | 335 | FD_ZERO(&fds); 336 | FD_SET(fd, &fds); 337 | 338 | return select(fd + 1, &fds, NULL, NULL, &tv); 339 | } 340 | 341 | /* 342 | * Returns: 343 | * >0 Колво байт 344 | * 0 Соединение закрыто 345 | * -1 error 346 | * -2 timeout 347 | **/ 348 | int SimpleRedisClient::wright_select(int fd, int timeout ) const 349 | { 350 | struct timeval tv; 351 | fd_set fds; 352 | 353 | tv.tv_sec = timeout / 1000; 354 | tv.tv_usec = (timeout % 1000)*1000; 355 | 356 | FD_ZERO(&fds); 357 | FD_SET(fd, &fds); 358 | 359 | return select(fd+1, NULL, &fds, NULL, &tv); 360 | } 361 | 362 | void SimpleRedisClient::LogLevel(int l) 363 | { 364 | debug = l; 365 | } 366 | 367 | int SimpleRedisClient::LogLevel(void) 368 | { 369 | return debug; 370 | } 371 | 372 | int SimpleRedisClient::getError(void) 373 | { 374 | return last_error; 375 | } 376 | 377 | int SimpleRedisClient::redis_raw_send(char recvtype,const char *dataCommand) 378 | { 379 | int rc = send_data(dataCommand); 380 | 381 | if (rc < 0) 382 | { 383 | if(debug) printf("Данные не отправлены [RC_ERR_SEND]"); 384 | reconect(); 385 | return RC_ERR_SEND; 386 | } 387 | 388 | if (rc != (int) strlen(dataCommand)) 389 | { 390 | if(debug) printf("Ответ не получен [RC_ERR_TIMEOUT]"); 391 | reconect(); 392 | return RC_ERR_TIMEOUT; 393 | } 394 | 395 | 396 | bzero(buffer,buffer_size); 397 | rc = read_select(fd, timeout); 398 | 399 | if(debug) printf("REDIS read_select=%d\n", rc); 400 | if (rc > 0) 401 | { 402 | 403 | int offset = 0; 404 | do{ 405 | rc = recv(fd, buffer + offset, buffer_size - offset, 0); 406 | 407 | if(rc < 0) 408 | { 409 | return CR_ERR_RECV; 410 | } 411 | 412 | if(rc >= buffer_size - offset && buffer_size * 2 > max_buffer_size) 413 | { 414 | char nullbuf[1000]; 415 | int r = 0; 416 | while( (r = recv(fd, nullbuf, 1000, 0)) >= 0) 417 | { 418 | if(debug) printf("REDIS read %d byte\n", r); 419 | } 420 | 421 | last_error = RC_ERR_DATA_BUFFER_OVERFLOW; 422 | break; 423 | } 424 | else if(rc >= buffer_size - offset && buffer_size * 2 < max_buffer_size) 425 | { 426 | if(debug) printf("REDIS Удвоение размера буфера до %d\t[rc=%d, buffer_size=%d, offset=%d]\n",buffer_size *2, rc, buffer_size, offset); 427 | 428 | int last_buffer_size = buffer_size; 429 | char* tbuf = buffer; 430 | 431 | buffer_size *= 2; 432 | buffer = new char[buffer_size]; 433 | 434 | delete buf; 435 | buf = new char[buffer_size]; 436 | 437 | memcpy(buffer, tbuf, last_buffer_size); 438 | offset = last_buffer_size; 439 | } 440 | else 441 | { 442 | break; 443 | } 444 | 445 | }while(1); 446 | if(debug > 3) printf("REDIS BUF: recv:%d buffer[%s]",rc, buffer); 447 | 448 | char prefix = buffer[0]; 449 | if (recvtype != RC_ANY && prefix != recvtype && prefix != RC_ERROR) 450 | { 451 | printf("\x1b[31m[fd=%d]REDIS RC_ERR_PROTOCOL[%c]:%s\x1b[0m\n",fd, recvtype, buffer); 452 | return RC_ERR_PROTOCOL; 453 | } 454 | 455 | char *p; 456 | int len = 0; 457 | switch (prefix) 458 | { 459 | case RC_ERROR: 460 | printf("\x1b[31mREDIS[fd=%d] RC_ERROR:%s\x1b[0m\n",fd,buffer); 461 | data = buffer; 462 | data_size = rc; 463 | return rc; 464 | case RC_INLINE: 465 | if(debug) printf("\x1b[33mREDIS[fd=%d] RC_INLINE:%s\x1b[0m\n", fd,buffer); 466 | data_size = strlen(buffer+1)-2; 467 | data = buffer+1; 468 | data[data_size] = 0; 469 | return rc; 470 | case RC_INT: 471 | if(debug) printf("\x1b[33mREDIS[fd=%d] RC_INT:%s\x1b[0m\n",fd, buffer); 472 | data = buffer+1; 473 | data_size = rc; 474 | return rc; 475 | case RC_BULK: 476 | if(debug) printf("\x1b[33mREDIS[fd=%d] RC_BULK:%s\x1b[0m\n",fd, buffer); 477 | 478 | p = buffer; 479 | p++; 480 | 481 | if(*p == '-') 482 | { 483 | data = 0; 484 | data_size = -1; 485 | return rc; 486 | } 487 | 488 | while(*p != '\r') { 489 | len = (len*10)+(*p - '0'); 490 | p++; 491 | } 492 | 493 | /* Now p points at '\r', and the len is in bulk_len. */ 494 | if(debug > 3) printf("%d\n", len); 495 | 496 | data = p+2; 497 | data_size = len; 498 | data[data_size] = 0; 499 | 500 | return rc; 501 | case RC_MULTIBULK: 502 | if(debug) printf("\x1b[33mREDIS[fd=%d] RC_MULTIBULK[Len=%d]:%s\x1b[0m\n", fd, rc, buffer); 503 | data = buffer; 504 | 505 | p = buffer; 506 | p++; 507 | int delta = 0; 508 | multibulk_arg = read_int(p, &delta); 509 | if(multibulk_arg < 1) 510 | { 511 | data = 0; 512 | data_size = -1; 513 | if(debug > 5) printf("\x1b[33mREDIS RC_MULTIBULK data_size = 0\x1b[0m\n"); 514 | return rc; 515 | } 516 | 517 | data_size = multibulk_arg; 518 | 519 | answer_multibulk = new char*[multibulk_arg]; 520 | 521 | p+= delta + 3; 522 | 523 | for(int i =0; i< multibulk_arg; i++) 524 | { 525 | if( buffer_size - 10 < p - buffer) 526 | { 527 | multibulk_arg = i-1; 528 | data_size = i - 1; 529 | if(debug) printf("\x1b[33mREDIS Выход по приближению к концу буфера [p=%d|multibulk_arg=%d]\x1b[0m\n", (int)(p - buffer), multibulk_arg); 530 | last_error = RC_ERR_DATA_BUFFER_OVERFLOW; 531 | return rc; 532 | } 533 | 534 | len = 0; 535 | while(*p != '\r') { 536 | len = (len*10)+(*p - '0'); 537 | p++; 538 | } 539 | 540 | p+=2; 541 | answer_multibulk[i] = p; 542 | 543 | p+= len; 544 | 545 | if( buffer_size - 1 < p - buffer ) 546 | { 547 | multibulk_arg = i-1; 548 | data_size = i - 1; 549 | if(debug) printf("\x1b[33mREDIS Выход по приближению к концу буфера [p=%d|multibulk_arg=%d]\x1b[0m\n", (int)(p - buffer), multibulk_arg); 550 | last_error = RC_ERR_DATA_BUFFER_OVERFLOW; 551 | return rc; 552 | } 553 | 554 | 555 | *p = 0; 556 | p+= 3; 557 | } 558 | 559 | return rc; 560 | } 561 | 562 | return rc; 563 | } 564 | else if (rc == 0) 565 | { 566 | if(debug) printf("Соединение закрыто [RC_ERR_CONECTION_CLOSE]"); 567 | reconect(); 568 | return RC_ERR_CONECTION_CLOSE; // Соединение закрыто 569 | } 570 | else 571 | { 572 | if(debug) printf("Не пришли данные от redis[RC_ERR]"); 573 | return RC_ERR; // error 574 | } 575 | } 576 | 577 | int SimpleRedisClient::redis_send(char recvtype, const char *format, ...) 578 | { 579 | debug = 5; 580 | if(fd == 0) 581 | { 582 | redis_conect(); 583 | } 584 | 585 | data = 0; 586 | data_size = 0; 587 | 588 | if(answer_multibulk != 0) 589 | { 590 | delete[] answer_multibulk; 591 | } 592 | multibulk_arg = -1; 593 | answer_multibulk = 0; 594 | 595 | va_list ap; 596 | va_start(ap, format); 597 | 598 | bzero(buffer,buffer_size); 599 | int rc = vsnprintf(buffer, buffer_size, format, ap); 600 | va_end(ap); 601 | 602 | if( rc < 0 ) 603 | { 604 | return RC_ERR_DATA_FORMAT; 605 | } 606 | 607 | if( rc >= buffer_size ) 608 | { 609 | return RC_ERR_BUFFER_OVERFLOW; // Не хватило буфера 610 | } 611 | 612 | if(debug > 3 ) printf("SEND:%s",buffer); 613 | 614 | return redis_raw_send(recvtype, buffer); 615 | } 616 | 617 | /** 618 | * Отправляет данные 619 | * @param buf 620 | * @return 621 | */ 622 | int SimpleRedisClient::send_data( const char *buf ) const 623 | { 624 | fd_set fds; 625 | struct timeval tv; 626 | int sent = 0; 627 | 628 | /* NOTE: On Linux, select() modifies timeout to reflect the amount 629 | * of time not slept, on other systems it is likely not the same */ 630 | tv.tv_sec = timeout / 1000; 631 | tv.tv_usec = (timeout % 1000)*1000; 632 | 633 | int tosend = strlen(buf); // При отправке бинарных данных возможны баги. 634 | 635 | while (sent < tosend) 636 | { 637 | FD_ZERO(&fds); 638 | FD_SET(fd, &fds); 639 | 640 | int rc = select(fd + 1, NULL, &fds, NULL, &tv); 641 | 642 | if (rc > 0) 643 | { 644 | rc = send(fd, buf + sent, tosend - sent, 0); 645 | if (rc < 0) 646 | { 647 | return -1; 648 | } 649 | sent += rc; 650 | } 651 | else if (rc == 0) /* timeout */ 652 | { 653 | break; 654 | } 655 | else 656 | { 657 | return -1; 658 | } 659 | } 660 | 661 | return sent; 662 | } 663 | 664 | /** 665 | * public: 666 | */ 667 | 668 | void SimpleRedisClient::setPort(int Port) 669 | { 670 | port = Port; 671 | } 672 | 673 | void SimpleRedisClient::setHost(const char* Host) 674 | { 675 | if(host != 0) 676 | { 677 | delete host; 678 | } 679 | 680 | host = new char[64]; 681 | bzero(host, 64); 682 | memcpy(host,Host,strlen(Host)); 683 | } 684 | 685 | /** 686 | * Соединение с редисом. 687 | */ 688 | int SimpleRedisClient::redis_conect(const char* Host,int Port) 689 | { 690 | setPort(Port); 691 | setHost(Host); 692 | return redis_conect(); 693 | } 694 | 695 | int SimpleRedisClient::redis_conect(const char* Host,int Port, int TimeOut) 696 | { 697 | setPort(Port); 698 | setHost(Host); 699 | setTimeout(TimeOut); 700 | return redis_conect(); 701 | } 702 | 703 | int SimpleRedisClient::reconect() 704 | { 705 | 706 | if(debug > 1) printf("\x1b[31mredis reconect[%s:%d]\x1b[0m\n", host, port); 707 | 708 | redis_close(); 709 | if(!redis_conect()) 710 | { 711 | return false; 712 | } 713 | 714 | if(lastAuthPw != NULL ) 715 | { 716 | printf("\x1b[31mredis reconect lastAuthPw=%s\x1b[0m\n", lastAuthPw); 717 | if(redis_send( RC_INLINE, "AUTH %s\r\n", lastAuthPw)) 718 | { 719 | return false; 720 | } 721 | } 722 | 723 | if(lastSelectDBIndex != 0 ) 724 | { 725 | if( !selectDB(lastSelectDBIndex) ) 726 | { 727 | return false; 728 | } 729 | } 730 | 731 | return true; 732 | } 733 | 734 | int SimpleRedisClient::redis_conect() 735 | { 736 | if(host == 0) 737 | { 738 | setHost("127.0.0.1"); 739 | } 740 | 741 | if(debug > 1) printf("\x1b[32mredis host:%s %d\x1b[0m\n", host, port); 742 | 743 | debug = 9; 744 | int rc; 745 | struct sockaddr_in sa; 746 | bzero(&sa, sizeof(sa)); 747 | 748 | sa.sin_family = AF_INET; 749 | sa.sin_port = htons(port); 750 | 751 | if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 || setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&yes, sizeof(yes)) == -1 || setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&yes, sizeof(yes)) == -1) 752 | { 753 | if(debug) printf("open error %d\n", fd); 754 | } 755 | 756 | struct addrinfo hints, *info = NULL; 757 | bzero(&hints, sizeof(hints)); 758 | 759 | if (inet_aton(host, &sa.sin_addr) == 0) 760 | { 761 | hints.ai_family = AF_INET; 762 | hints.ai_socktype = SOCK_STREAM; 763 | int err = getaddrinfo(host, NULL, &hints, &info); 764 | if (err) 765 | { 766 | printf("\x1b[31mgetaddrinfo error: %s [%s]\x1b[0m\n", gai_strerror(err), host); 767 | if(debug) printf("\x1b[31mgetaddrinfo error\x1b[0m\n"); 768 | return -1; 769 | } 770 | 771 | memcpy(&sa.sin_addr.s_addr, &(info->ai_addr->sa_data[2]), sizeof(in_addr_t)); 772 | freeaddrinfo(info); 773 | } 774 | 775 | int flags = fcntl(fd, F_GETFL); 776 | if ((rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) < 0) 777 | { 778 | printf("\x1b[31mSetting socket non-blocking failed with: %d\x1b[0m\n", rc); 779 | if(debug) printf("\x1b[31mSetting socket non-blocking failed\x1b[0m\n"); 780 | return -1; 781 | } 782 | 783 | if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) 784 | { 785 | if (errno != EINPROGRESS) 786 | { 787 | return RC_ERR; 788 | } 789 | 790 | if (wright_select(fd, timeout) > 0) 791 | { 792 | int err = 0; 793 | unsigned int len = sizeof(err); 794 | if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == -1 || err) 795 | { 796 | return RC_ERR; 797 | } 798 | } 799 | else /* timeout or select error */ 800 | { 801 | return RC_ERR_TIMEOUT; 802 | } 803 | } 804 | if(debug > RC_LOG_DEBUG) printf("open ok %d\n", fd); 805 | 806 | return fd; 807 | } 808 | 809 | char** SimpleRedisClient::getMultiBulkData() 810 | { 811 | return answer_multibulk; 812 | } 813 | 814 | /** 815 | * Вернёт количество ответов. Или -1 если последняя операция вернула что либо кроме множества ответов. 816 | * @return 817 | */ 818 | int SimpleRedisClient::getMultiBulkDataAmount() 819 | { 820 | return multibulk_arg; 821 | } 822 | 823 | /** 824 | * Работает только после запроса данных которые возвращаются как множество ответов 825 | * @param i Номер ответа в множестве отвкетов 826 | * @return Вернёт ноль в случаи ошибки или указатель на данные 827 | */ 828 | char* SimpleRedisClient::getData(int i) const 829 | { 830 | if(multibulk_arg > i) 831 | { 832 | return answer_multibulk[i]; 833 | } 834 | return 0; 835 | } 836 | 837 | /** 838 | * Выбор бызы данных 839 | * @param index 840 | * @see http://redis.io/commands/select 841 | */ 842 | int SimpleRedisClient::selectDB(int index) 843 | { 844 | lastSelectDBIndex = index; 845 | return redis_send(RC_INLINE, "SELECT %d\r\n", index); 846 | } 847 | 848 | 849 | /** 850 | * Возвращает все члены множества, сохранённого в указанном ключе. Эта команда - просто упрощённый синтаксис для SINTER. 851 | * SMEMBERS key 852 | * Время выполнения: O(N). 853 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-smembers 854 | * @see http://redis.io/commands/smembers 855 | * @param key 856 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 857 | */ 858 | int SimpleRedisClient::smembers(const char *key) 859 | { 860 | return redis_send(RC_MULTIBULK, "SMEMBERS %s\r\n", key); 861 | } 862 | 863 | /** 864 | * Возвращает все члены множества, сохранённого в указанном ключе. Эта команда - просто упрощённый синтаксис для SINTER. 865 | * SMEMBERS key 866 | * Время выполнения: O(N). 867 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-smembers 868 | * @see http://redis.io/commands/smembers 869 | * @param key 870 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 871 | */ 872 | int SimpleRedisClient::smembers_printf(const char *format, ...) 873 | { 874 | REDIS_PRINTF_MACRO_CODE(RC_MULTIBULK, "SMEMBERS") 875 | } 876 | 877 | /** 878 | * Returns the set cardinality (number of elements) of the set stored at key. 879 | * @see http://redis.io/commands/scard 880 | * @param key 881 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 882 | */ 883 | int SimpleRedisClient::scard(const char *key) 884 | { 885 | return redis_send(RC_INT, "SCARD %s\r\n", key); 886 | } 887 | 888 | /** 889 | * Returns the set cardinality (number of elements) of the set stored at key. 890 | * @see http://redis.io/commands/scard 891 | * @param key 892 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 893 | */ 894 | int SimpleRedisClient::scard_printf(const char *format, ...) 895 | { 896 | REDIS_PRINTF_MACRO_CODE(RC_INT, "SCARD") 897 | } 898 | 899 | /** 900 | * Ни ключь ни значение не должны содержать "\r\n" 901 | * @param key 902 | * @param val 903 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 904 | */ 905 | int SimpleRedisClient::set(const char *key, const char *val) 906 | { 907 | return redis_send( RC_INLINE, "SET %s %s\r\n", key, val); 908 | } 909 | 910 | int SimpleRedisClient::set_printf(const char *format, ...) 911 | { 912 | REDIS_PRINTF_MACRO_CODE(RC_INLINE, "SET") 913 | } 914 | 915 | SimpleRedisClient& SimpleRedisClient::operator=(const char *key_val) 916 | { 917 | redis_send( RC_INLINE, "SET %s\r\n", key_val); 918 | return *this; 919 | } 920 | 921 | 922 | int SimpleRedisClient::setex(const char *key, const char *val, int seconds) 923 | { 924 | return redis_send(RC_INLINE, "SETEX %s %d %s\r\n",key, seconds, val); 925 | } 926 | 927 | int SimpleRedisClient::setex_printf(int seconds, const char *key, const char *format, ...) 928 | { 929 | va_list ap; 930 | va_start(ap, format); 931 | 932 | bzero(buf, buffer_size); 933 | int rc = vsnprintf(buf, buffer_size, format, ap); 934 | va_end(ap); 935 | 936 | if( rc >= buffer_size ) 937 | { 938 | return RC_ERR_BUFFER_OVERFLOW;; // Не хватило буфера 939 | } 940 | 941 | if(rc < 0) 942 | { 943 | return RC_ERR_DATA_FORMAT; 944 | } 945 | 946 | return redis_send(RC_INLINE, "SETEX %s %d %s\r\n",key, seconds, buf); 947 | } 948 | 949 | int SimpleRedisClient::setex_printf(const char *format, ...) 950 | { 951 | REDIS_PRINTF_MACRO_CODE(RC_INLINE, "SETEX") 952 | } 953 | 954 | 955 | int SimpleRedisClient::get(const char *key) 956 | { 957 | return redis_send( RC_BULK, "GET %s\r\n", key); 958 | } 959 | 960 | 961 | int SimpleRedisClient::get_printf( const char *format, ...) 962 | { 963 | REDIS_PRINTF_MACRO_CODE(RC_BULK, "GET") 964 | } 965 | 966 | /** 967 | * Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members. 968 | * An error is returned when the value stored at key is not a set. 969 | * @see http://redis.io/commands/sadd 970 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-sadd 971 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 972 | */ 973 | int SimpleRedisClient::sadd(const char *key, const char *member) 974 | { 975 | return redis_send(RC_INT, "SADD %s %s\r\n", key, member); 976 | } 977 | 978 | /** 979 | * Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members. 980 | * An error is returned when the value stored at key is not a set. 981 | * @see http://redis.io/commands/sadd 982 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-sadd 983 | * @param format 984 | * @param ... Ключь Значение (через пробел, в значении нет пробелов) 985 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 986 | */ 987 | int SimpleRedisClient::sadd_printf(const char *format, ...) 988 | { 989 | REDIS_PRINTF_MACRO_CODE(RC_INT, "SADD") 990 | } 991 | 992 | /** 993 | * Remove the specified members from the set stored at key. 994 | * Specified members that are not a member of this set are ignored. 995 | * If key does not exist, it is treated as an empty set and this command returns 0. 996 | * An error is returned when the value stored at key is not a set. 997 | * 998 | * @see http://redis.io/commands/srem 999 | * @param key 1000 | * @param member 1001 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1002 | */ 1003 | int SimpleRedisClient::srem(const char *key, const char *member) 1004 | { 1005 | return redis_send(RC_INT, "SREM %s %s\r\n", key, member); 1006 | } 1007 | 1008 | /** 1009 | * Remove the specified members from the set stored at key. 1010 | * Specified members that are not a member of this set are ignored. If key does not exist, it is treated as an empty set and this command returns 0. 1011 | * An error is returned when the value stored at key is not a set. 1012 | * @see http://redis.io/commands/srem 1013 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-srem 1014 | * @param format 1015 | * @param ... Ключь Значение (через пробел, в значении нет пробелов) 1016 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1017 | */ 1018 | int SimpleRedisClient::srem_printf(const char *format, ...) 1019 | { 1020 | REDIS_PRINTF_MACRO_CODE(RC_INT, "SREM") 1021 | } 1022 | 1023 | 1024 | char* SimpleRedisClient::operator[] (const char *key) 1025 | { 1026 | redis_send( RC_BULK, "GET %s\r\n", key); 1027 | return getData(); 1028 | } 1029 | 1030 | SimpleRedisClient::operator char* () const 1031 | { 1032 | return getData(); 1033 | } 1034 | 1035 | /** 1036 | * @todo ЗАДОКУМЕНТИРОВАТЬ 1037 | * @return 1038 | */ 1039 | SimpleRedisClient::operator int () const 1040 | { 1041 | if(data_size < 1) 1042 | { 1043 | printf("SimpleRedisClient::operator int (%u) \n", data_size); 1044 | return data_size; 1045 | } 1046 | 1047 | if(getData() == 0) 1048 | { 1049 | printf("SimpleRedisClient::operator int (%u) \n", data_size); 1050 | return -1; 1051 | } 1052 | 1053 | int d = 0; 1054 | int r = read_int(getData(), &d); 1055 | 1056 | printf("SimpleRedisClient::operator int (%u|res=%d) \n", data_size, r); 1057 | 1058 | return r; 1059 | } 1060 | 1061 | /** 1062 | * @todo ЗАДОКУМЕНТИРОВАТЬ 1063 | * @return 1064 | */ 1065 | SimpleRedisClient::operator long () const 1066 | { 1067 | if(data_size < 1) 1068 | { 1069 | printf("SimpleRedisClient::operator long (%u) \n", data_size); 1070 | return data_size; 1071 | } 1072 | 1073 | if(getData() == 0) 1074 | { 1075 | printf("SimpleRedisClient::operator long (%u) \n", data_size); 1076 | return -1; 1077 | } 1078 | 1079 | int d = 0; 1080 | int r = read_long(getData(), &d); 1081 | 1082 | printf("SimpleRedisClient::operator long (%u|res=%d) \n", data_size, r); 1083 | 1084 | return r; 1085 | } 1086 | 1087 | int SimpleRedisClient::getset(const char *key, const char *set_val) 1088 | { 1089 | return redis_send( RC_BULK, "GETSET %s %s\r\n", key, set_val); 1090 | } 1091 | 1092 | int SimpleRedisClient::getset_printf(const char *format, ...) 1093 | { 1094 | REDIS_PRINTF_MACRO_CODE(RC_BULK, "GETSET") 1095 | } 1096 | 1097 | int SimpleRedisClient::ping() 1098 | { 1099 | return redis_send( RC_INLINE, "PING\r\n"); 1100 | } 1101 | 1102 | int SimpleRedisClient::echo(const char *message) 1103 | { 1104 | return redis_send( RC_BULK, "ECHO %s\r\n", message);; 1105 | } 1106 | 1107 | int SimpleRedisClient::quit() 1108 | { 1109 | return redis_send( RC_INLINE, "QUIT\r\n"); 1110 | } 1111 | 1112 | int SimpleRedisClient::auth(const char *password) 1113 | { 1114 | if(lastAuthPw != NULL) 1115 | { 1116 | delete[] lastAuthPw; 1117 | } 1118 | 1119 | int pwLen = strlen(password); 1120 | lastAuthPw = new char[pwLen+1]; 1121 | memcpy(lastAuthPw, password, pwLen); 1122 | lastAuthPw[pwLen] = 0; 1123 | 1124 | printf("\x1b[32mredis new lastAuthPw[%d]=%s\x1b[0m\n", pwLen, lastAuthPw); 1125 | 1126 | return redis_send( RC_INLINE, "AUTH %s\r\n", password); 1127 | } 1128 | 1129 | 1130 | int SimpleRedisClient::getRedisVersion() 1131 | { 1132 | /* We can receive 2 version formats: x.yz and x.y.z, where x.yz was only used prior 1133 | * first 1.1.0 release(?), e.g. stable releases 1.02 and 1.2.6 */ 1134 | /* TODO check returned error string, "-ERR operation not permitted", to detect if 1135 | * server require password? */ 1136 | if (redis_send( RC_BULK, "INFO\r\n") == 0) 1137 | { 1138 | sscanf(buffer, "redis_version:%9d.%9d.%9d\r\n", &version_major, &version_minor, &version_patch); 1139 | return version_major; 1140 | } 1141 | 1142 | return 0; 1143 | } 1144 | 1145 | 1146 | int SimpleRedisClient::setnx(const char *key, const char *val) 1147 | { 1148 | return redis_send( RC_INT, "SETNX %s %s\r\n", key, val); 1149 | } 1150 | 1151 | int SimpleRedisClient::setnx_printf(const char *format, ...) 1152 | { 1153 | REDIS_PRINTF_MACRO_CODE(RC_INT, "SETNX") 1154 | } 1155 | 1156 | int SimpleRedisClient::append(const char *key, const char *val) 1157 | { 1158 | return redis_send(RC_INT, "APPEND %s %s\r\n", key, val); 1159 | } 1160 | 1161 | int SimpleRedisClient::append_printf(const char *format, ...) 1162 | { 1163 | REDIS_PRINTF_MACRO_CODE(RC_INT, "APPEND") 1164 | } 1165 | 1166 | int SimpleRedisClient::substr( const char *key, int start, int end) 1167 | { 1168 | return redis_send(RC_BULK, "SUBSTR %s %d %d\r\n", key, start, end); 1169 | } 1170 | 1171 | int SimpleRedisClient::exists( const char *key) 1172 | { 1173 | return redis_send( RC_INT, "EXISTS %s\r\n", key); 1174 | } 1175 | 1176 | int SimpleRedisClient::exists_printf(const char *format, ...) 1177 | { 1178 | REDIS_PRINTF_MACRO_CODE(RC_INT, "EXISTS") 1179 | } 1180 | 1181 | 1182 | /** 1183 | * Время выполнения: O(1) 1184 | * Удаление указанных ключей. Если переданный ключ не существует, операция для него не выполняется. Команда возвращает количество удалённых ключей. 1185 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-del 1186 | * @see http://redis.io/commands/del 1187 | * @param key 1188 | * @return 1189 | */ 1190 | int SimpleRedisClient::del( const char *key) 1191 | { 1192 | return redis_send( RC_INT, "DEL %s\r\n", key); 1193 | } 1194 | 1195 | int SimpleRedisClient::del_printf(const char *format, ...) 1196 | { 1197 | REDIS_PRINTF_MACRO_CODE(RC_INT, "DEL") 1198 | } 1199 | 1200 | /** 1201 | * Удаляет все найденые ключи, тоесть ищет их командой keys и удаляет каждый найденый ключь. 1202 | * @param key 1203 | * @return Вернёт -1 или количество удалёных ключей 1204 | * @todo Реализовать более быстрый способ работы 1205 | */ 1206 | int SimpleRedisClient::delete_keys( const char *key) 1207 | { 1208 | if(keys(key)) 1209 | { 1210 | if(getDataSize() < 1 || getBufferSize() < 1) 1211 | { 1212 | return 0; 1213 | } 1214 | 1215 | char **ptr_data = new char*[getDataSize()]; 1216 | 1217 | // Выделяем память для buf_data 1218 | char *buf_data = new char[ getBufferSize() ]; 1219 | memcpy(buf_data, getData(), getBufferSize()); 1220 | 1221 | long int offset = buf_data - getData(); // Опасное дело! 1222 | int num_keys = getDataSize(); 1223 | for(int i =0; i< num_keys; i++) 1224 | { 1225 | ptr_data[i] = getData(i) + offset; 1226 | } 1227 | 1228 | for(int i =0; i< num_keys; i++) 1229 | { 1230 | printf("del[%d]:%s\n", i, ptr_data[i]); 1231 | del(ptr_data[i]); 1232 | } 1233 | 1234 | // [SimpleRedisClient.cpp:1171]: (error) Mismatching allocation and deallocation: buf_data 1235 | // Очищаем buf_data 1236 | delete[] buf_data; 1237 | delete[] ptr_data; 1238 | return num_keys; 1239 | } 1240 | 1241 | return -1; 1242 | } 1243 | 1244 | /** 1245 | * Удаляет все найденые ключи, тоесть ищет их командой keys и удаляет каждый найденый ключь. 1246 | * @param key 1247 | * @return Вернёт -1 или количество удалёных ключей 1248 | * @todo Реализовать более быстрый способ работы 1249 | */ 1250 | int SimpleRedisClient::delete_keys_printf(const char *format, ...) 1251 | { 1252 | va_list ap; 1253 | va_start(ap, format); 1254 | bzero(buf, buffer_size); 1255 | int rc = vsnprintf(buf, buffer_size, format, ap); 1256 | va_end(ap); 1257 | if( rc >= buffer_size ) return RC_ERR_BUFFER_OVERFLOW; 1258 | if(rc < 0) return RC_ERR_DATA_FORMAT; 1259 | 1260 | if(redis_send(RC_MULTIBULK, "KEYS %s\r\n", buf)) 1261 | { 1262 | if(getDataSize() < 1 || getBufferSize() < 1) 1263 | { 1264 | return 0; 1265 | } 1266 | 1267 | char **ptr_data = new char*[getDataSize()]; 1268 | 1269 | // Выделяем память для buf_data 1270 | char *buf_data = new char[ getBufferSize() ]; 1271 | memcpy(buf_data, getData(), getBufferSize()); 1272 | 1273 | long int offset = buf_data - getData(); // Опасное дело! 1274 | int num_keys = getDataSize(); 1275 | for(int i =0; i< num_keys; i++) 1276 | { 1277 | ptr_data[i] = getData(i) + offset; 1278 | } 1279 | 1280 | 1281 | for(int i =0; i< num_keys; i++) 1282 | { 1283 | printf("del[%d]:%s\n", i, ptr_data[i]); 1284 | del(ptr_data[i]); 1285 | } 1286 | 1287 | // Очищаем buf_data 1288 | delete[] buf_data; 1289 | 1290 | delete[] ptr_data; 1291 | return num_keys; 1292 | } 1293 | return -1; 1294 | } 1295 | 1296 | 1297 | int SimpleRedisClient::type( const char *key) 1298 | { 1299 | return redis_send( RC_INLINE, "TYPE %s\r\n", key); 1300 | } 1301 | 1302 | int SimpleRedisClient::keys( const char *pattern) 1303 | { 1304 | return redis_send(RC_MULTIBULK, "KEYS %s\r\n", pattern); 1305 | } 1306 | 1307 | int SimpleRedisClient::keys_printf(const char *format, ...) 1308 | { 1309 | REDIS_PRINTF_MACRO_CODE(RC_MULTIBULK, "KEYS") 1310 | } 1311 | 1312 | 1313 | int SimpleRedisClient::randomkey() 1314 | { 1315 | return redis_send( RC_BULK, "RANDOMKEY\r\n"); 1316 | } 1317 | 1318 | int SimpleRedisClient::flushall(void) 1319 | { 1320 | return redis_send( RC_INLINE, "FLUSHALL\r\n"); 1321 | } 1322 | 1323 | int SimpleRedisClient::rename( const char *key, const char *new_key_name) 1324 | { 1325 | return redis_send( RC_INLINE, "RENAME %s %s\r\n", key, new_key_name); 1326 | } 1327 | 1328 | int SimpleRedisClient::rename_printf(const char *format, ...) 1329 | { 1330 | REDIS_PRINTF_MACRO_CODE(RC_INLINE, "RENAME") 1331 | } 1332 | 1333 | int SimpleRedisClient::renamenx( const char *key, const char *new_key_name) 1334 | { 1335 | return redis_send( RC_INT, "RENAMENX %s %s\r\n", key, new_key_name); 1336 | } 1337 | 1338 | int SimpleRedisClient::renamenx_printf(const char *format, ...) 1339 | { 1340 | REDIS_PRINTF_MACRO_CODE(RC_INT, "RENAMENX") 1341 | } 1342 | 1343 | /** 1344 | * Return the number of keys in the selected database 1345 | */ 1346 | int SimpleRedisClient::dbsize() 1347 | { 1348 | return redis_send( RC_INT, "DBSIZE\r\n"); 1349 | } 1350 | 1351 | int SimpleRedisClient::expire( const char *key, int secs) 1352 | { 1353 | return redis_send( RC_INT, "EXPIRE %s %d\r\n", key, secs); 1354 | } 1355 | 1356 | int SimpleRedisClient::expire_printf(const char *format, ...) 1357 | { 1358 | REDIS_PRINTF_MACRO_CODE(RC_INT, "EXPIRE") 1359 | } 1360 | 1361 | 1362 | int SimpleRedisClient::ttl( const char *key) 1363 | { 1364 | return redis_send( RC_INT, "TTL %s\r\n", key); 1365 | } 1366 | 1367 | int SimpleRedisClient::ttl_printf(const char *format, ...) 1368 | { 1369 | REDIS_PRINTF_MACRO_CODE(RC_INT, "TTL") 1370 | } 1371 | 1372 | // Списки 1373 | 1374 | int SimpleRedisClient::lpush(const char *key, const char *val) 1375 | { 1376 | return redis_send( RC_INT, "LPUSH %s %s\r\n", key, val); 1377 | } 1378 | 1379 | int SimpleRedisClient::lpush_printf(const char *format, ...) 1380 | { 1381 | REDIS_PRINTF_MACRO_CODE(RC_INT, "LPUSH") 1382 | } 1383 | 1384 | int SimpleRedisClient::rpush(const char *key, const char *val) 1385 | { 1386 | return redis_send( RC_INT, "RPUSH %s %s\r\n", key, val); 1387 | } 1388 | 1389 | int SimpleRedisClient::rpush_printf(const char *format, ...) 1390 | { 1391 | REDIS_PRINTF_MACRO_CODE(RC_INT, "RPUSH") 1392 | } 1393 | 1394 | /** 1395 | * LTRIM mylist 1 -1 1396 | */ 1397 | int SimpleRedisClient::ltrim(const char *key, int start_pos, int count_elem) 1398 | { 1399 | return redis_send( RC_INLINE, "LTRIM %s %d %d\r\n", key, start_pos, count_elem); 1400 | } 1401 | 1402 | /** 1403 | * LTRIM mylist 1 -1 1404 | */ 1405 | int SimpleRedisClient::ltrim_printf(const char *format, ...) 1406 | { 1407 | REDIS_PRINTF_MACRO_CODE(RC_INLINE, "LTRIM") 1408 | } 1409 | 1410 | /** 1411 | * Выборка с конца очереди (то что попало в очередь раньше других), если все сообщения добавлялись с rpush 1412 | * @param key 1413 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1414 | */ 1415 | int SimpleRedisClient::lpop(const char *key) 1416 | { 1417 | return redis_send( RC_INT, "LPUSH %s\r\n", key); 1418 | } 1419 | 1420 | /** 1421 | * Выборка с начала очереди (то что попало в очередь позже других), если все сообщения добавлялись с rpush 1422 | * @param key 1423 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1424 | */ 1425 | int SimpleRedisClient::lpop_printf(const char *format, ...) 1426 | { 1427 | REDIS_PRINTF_MACRO_CODE(RC_BULK, "LPOP") 1428 | } 1429 | 1430 | int SimpleRedisClient::rpop(const char *key) 1431 | { 1432 | return redis_send( RC_INT, "RPUSH %s\r\n", key); 1433 | } 1434 | 1435 | int SimpleRedisClient::rpop_printf(const char *format, ...) 1436 | { 1437 | REDIS_PRINTF_MACRO_CODE(RC_BULK, "RPOP") 1438 | } 1439 | 1440 | int SimpleRedisClient::llen(const char *key) 1441 | { 1442 | return redis_send( RC_INT, "LLEN %s\r\n", key); 1443 | } 1444 | 1445 | int SimpleRedisClient::llen_printf(const char *format, ...) 1446 | { 1447 | REDIS_PRINTF_MACRO_CODE(RC_INT, "LLEN") 1448 | } 1449 | 1450 | 1451 | int SimpleRedisClient::lrem(const char *key, int n,const char* val) 1452 | { 1453 | return redis_send( RC_INT, "LLEN %s %d %s \r\n", key, n, val); 1454 | } 1455 | 1456 | int SimpleRedisClient::lrem_printf(const char *format, ...) 1457 | { 1458 | REDIS_PRINTF_MACRO_CODE(RC_INT, "LREM") 1459 | } 1460 | 1461 | 1462 | int SimpleRedisClient::lrange(const char *key, int start, int stop) 1463 | { 1464 | return redis_send( RC_INT, "LRANGE %s %d %d\r\n", key, start, stop); 1465 | } 1466 | 1467 | int SimpleRedisClient::lrange_printf(const char *format, ...) 1468 | { 1469 | REDIS_PRINTF_MACRO_CODE(RC_MULTIBULK, "LRANGE") 1470 | } 1471 | 1472 | 1473 | int SimpleRedisClient::incr(const char *key) 1474 | { 1475 | return redis_send( RC_INT, "INCR %s\r\n", key); 1476 | } 1477 | 1478 | int SimpleRedisClient::incr_printf(const char *format, ...) 1479 | { 1480 | REDIS_PRINTF_MACRO_CODE(RC_INT, "INCR") 1481 | } 1482 | 1483 | int SimpleRedisClient::decr(const char *key) 1484 | { 1485 | return redis_send( RC_INT, "DECR %s\r\n", key); 1486 | } 1487 | 1488 | int SimpleRedisClient::decr_printf(const char *format, ...) 1489 | { 1490 | REDIS_PRINTF_MACRO_CODE(RC_INT, "DECR") 1491 | } 1492 | 1493 | int SimpleRedisClient::operator +=( const char *key) 1494 | { 1495 | return redis_send( RC_INT, "INCR %s\r\n", key); 1496 | } 1497 | 1498 | int SimpleRedisClient::operator -=( const char *key) 1499 | { 1500 | return redis_send( RC_INT, "DECR %s\r\n", key); 1501 | } 1502 | 1503 | /** 1504 | * 1505 | * @param TimeOut 1506 | */ 1507 | void SimpleRedisClient::setTimeout( int TimeOut) 1508 | { 1509 | timeout = TimeOut; 1510 | } 1511 | 1512 | /** 1513 | * Закрывает соединение 1514 | */ 1515 | void SimpleRedisClient::redis_close() 1516 | { 1517 | if(debug > RC_LOG_DEBUG) printf("close ok %d\n", fd); 1518 | if(fd != 0 ) 1519 | { 1520 | close(fd); 1521 | } 1522 | } 1523 | 1524 | 1525 | SimpleRedisClient::operator bool () const 1526 | { 1527 | return fd != 0; 1528 | } 1529 | 1530 | int SimpleRedisClient::operator == (bool d) 1531 | { 1532 | return (fd != 0) == d; 1533 | } 1534 | 1535 | 1536 | char* SimpleRedisClient::getData() const 1537 | { 1538 | return data; 1539 | } 1540 | 1541 | int SimpleRedisClient::getDataSize() const 1542 | { 1543 | return data_size; 1544 | } 1545 | 1546 | -------------------------------------------------------------------------------- /for-redis-2.6/SimpleRedisClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SimpleRedisClient.h 3 | * Author: victor 4 | * 5 | * Created on 10 Август 2013 г., 22:26 6 | */ 7 | 8 | #ifndef SIMPLEREDISCLIENT_H 9 | #define SIMPLEREDISCLIENT_H 10 | 11 | 12 | #define RC_NULL 0 13 | #define RC_ERR -1 14 | 15 | #define RC_ERR_CONECTION_CLOSE -2 16 | #define RC_ERR_SEND -101 17 | #define RC_ERR_TIMEOUT -102 18 | #define CR_ERR_RECV -103 19 | 20 | #define RC_ERR_PROTOCOL -104 21 | #define RC_ERR_BUFFER_OVERFLOW -105 22 | #define RC_ERR_DATA_FORMAT -106 23 | 24 | #define RC_ERR_DATA_BUFFER_OVERFLOW -107 25 | 26 | 27 | #define RC_LOG_NONE 0 28 | #define RC_LOG_ERROR 1 29 | #define RC_LOG_WARN 2 30 | #define RC_LOG_LOG 3 31 | #define RC_LOG_DEBUG 4 32 | 33 | /** 34 | * Тип ожидаемых от редиса данных 35 | */ 36 | #define RC_ERROR '-' 37 | 38 | /** 39 | * Тип ожидаемых от редиса данных 40 | * Строка в ответе 41 | * @see http://redis.io/topics/protocol 42 | */ 43 | #define RC_INLINE '+' 44 | 45 | /** 46 | * Тип ожидаемых от редиса данных 47 | * Определяет длину аргумента ответа 48 | * -1 нет ответа 49 | * @see http://redis.io/topics/protocol 50 | */ 51 | #define RC_BULK '$' 52 | 53 | /** 54 | * Тип ожидаемых от редиса данных 55 | * Определяет количество аргументов ответа 56 | * -1 нет ответа 57 | * @see http://redis.io/topics/protocol 58 | */ 59 | #define RC_MULTIBULK '*' 60 | 61 | /** 62 | * Тип ожидаемых от редиса данных 63 | */ 64 | #define RC_INT ':' 65 | 66 | /** 67 | * Тип ожидаемых от редиса данных 68 | */ 69 | #define RC_ANY '?' 70 | 71 | /** 72 | * Тип ожидаемых от редиса данных 73 | */ 74 | #define RC_NONE ' ' 75 | 76 | int read_int(const char* buffer, char delimiter, int* delta); 77 | int read_int(const char* buffer, char delimiter); 78 | int read_int(const char* buffer, int* delta); 79 | 80 | long read_long(const char* buffer, char delimiter, int* delta); 81 | long read_long(const char* buffer, char delimiter); 82 | long read_long(const char* buffer, int* delta); 83 | 84 | class SimpleRedisClient 85 | { 86 | int fd = 0; 87 | int yes = 1; 88 | int timeout = 1000; 89 | 90 | char* buffer = 0; 91 | char* buf = 0; 92 | int buffer_size = 0; 93 | 94 | /** 95 | * Максимально допустимый размер буфера 96 | */ 97 | int max_buffer_size = 1000000; 98 | 99 | 100 | int port = 6379; 101 | char* host = 0; 102 | 103 | int version_major = -1; 104 | int version_minor = -1; 105 | int version_patch = -1; 106 | 107 | /** 108 | * Хранит количество пришедших данных в ответе. 109 | * Для списка это колво элементов для остальных типов это колво байт. 110 | */ 111 | unsigned int data_size = 0; 112 | 113 | char* data = 0; 114 | int answer_int = 0; 115 | 116 | int multibulk_arg = 0; 117 | char** answer_multibulk = 0; 118 | 119 | int debug = 0; 120 | 121 | int last_error = 0; 122 | 123 | private: 124 | 125 | /** 126 | * Запрещаем копирование для объектов донного класса 127 | * Если открыто соединение с редисом, а потом выполнена копия объекта 128 | * то при удалении любого из объектов в деструкторе соединение закроется. 129 | * ,а при удалении второго вообще ни чего хорошего ждать не надо. 130 | * 131 | * Возможно в следующих версиях библиотеки будет реализован адекватный конструктор копирования. 132 | */ 133 | SimpleRedisClient(const SimpleRedisClient& ) = delete; 134 | 135 | /** 136 | * Запрещаем копирование для объектов донного класса 137 | * Возможно в следующих версиях библиотеки будет реализован адекватный конструктор копирования. 138 | */ 139 | void operator=( const SimpleRedisClient& ) = delete; 140 | 141 | public: 142 | 143 | void LogLevel(int); 144 | int LogLevel(void); 145 | 146 | SimpleRedisClient(); 147 | 148 | void setPort(int Port); 149 | 150 | void setHost(const char* Host); 151 | 152 | virtual ~SimpleRedisClient(); 153 | 154 | int redis_conect(); 155 | int redis_conect(const char* Host, int Port); 156 | int redis_conect(const char* Host,int Port, int TimeOut); 157 | 158 | /* 159 | vector3 operator-=(float v); 160 | bool operator==(vector3 v); 161 | */ 162 | 163 | char** getMultiBulkData(); 164 | int getMultiBulkDataAmount(); 165 | 166 | /** 167 | * Ни ключь ни значение не должны содержать "\r\n" 168 | * @param key 169 | * @param val 170 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 171 | */ 172 | int set(const char *key, const char *val); 173 | 174 | /** 175 | * Операция set только с форматированием строки параметров. 176 | * Ключ от значения отделяется пробелом. 177 | * @param format 178 | * @param ... ключь пробел значение 179 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 180 | */ 181 | int set_printf(const char *format, ...); 182 | 183 | /** 184 | * 185 | * @param key Ключ 186 | * @param format 187 | * @param ... значение 188 | * @return 189 | int set_printf(const char *key, const char *format, ...); 190 | */ 191 | 192 | /** 193 | * Выполняет установку значения в редис 194 | * Ключ от значения отделяется пробелом. 195 | * @code rc = "MyKey MyValue"; 196 | * 197 | * 198 | * @param key_val 199 | * @return 200 | */ 201 | SimpleRedisClient& operator=(const char *key_val); 202 | 203 | /** 204 | * Вернёт значение ключа или 0 в случаии отсутсвия ключа или ошибки 205 | * Пример: 206 | * 207 | * char* val = rc["key"]; 208 | * if(val != 0) 209 | * { 210 | * printf("VAL:%s\n", val); 211 | * } 212 | * 213 | * Выдаётся указатьель на внутриний буфер чтения/записи ссылка потеряет актуальность при вызове любой функции на получение или запись данных. 214 | * Или по указаному адресу будут уже другие данные либо мусор. 215 | */ 216 | char* operator[] (const char *key); 217 | 218 | 219 | /** 220 | * Равносильно методу getData() 221 | * @return 222 | */ 223 | operator char* () const; 224 | 225 | /** 226 | * Равносильно методу getData() с преобразованием в int 227 | * @return 228 | */ 229 | operator int () const; 230 | 231 | /** 232 | * Равносильно методу getData() с преобразованием в long 233 | * @return 234 | */ 235 | operator long () const; 236 | 237 | /** 238 | * Инкриментирует значение ключа key, эквивалентно incr 239 | * @param key ключь в редисе 240 | * @return 241 | */ 242 | int operator +=( const char *key); 243 | 244 | /** 245 | * Декриментирует значение ключа key, эквивалентно decr 246 | * @param key ключь в редисе 247 | * @return 248 | */ 249 | int operator -=( const char *key); 250 | 251 | /** 252 | * Вернёт true если соединение установлено 253 | */ 254 | operator bool () const; 255 | 256 | /** 257 | * rc == true истино если соединение установлено 258 | * rc == false истино если соединение не установлено 259 | */ 260 | int operator == (bool); 261 | 262 | int incr(const char *key); 263 | int incr_printf(const char *format, ...); 264 | 265 | int decr(const char *key); 266 | int decr_printf(const char *format, ...); 267 | 268 | int setex(const char *key, const char *val, int seconds); 269 | int setex_printf(int seconds, const char *key, const char *format, ...); 270 | 271 | /** 272 | * Формат должен иметь вид: key seconds data 273 | * Где 274 | * key строковый ключ 275 | * seconds %d число секунд 276 | * data строковые данные 277 | * 278 | * @param format 279 | * @param ... 280 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 281 | */ 282 | int setex_printf(const char *format, ...); 283 | 284 | int get(const char *key); 285 | int get_printf( const char *format, ...); 286 | 287 | 288 | /** 289 | * Set the string value of a key and return its old value 290 | * @param key 291 | * @param set_val 292 | * @param get_val 293 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 294 | */ 295 | int getset(const char *key, const char *set_val); 296 | int getset_printf(const char *format, ...); 297 | 298 | /** 299 | * Ping the server 300 | */ 301 | int ping(); 302 | 303 | int echo(const char *message); 304 | 305 | int quit(); 306 | 307 | int auth(const char *password); 308 | 309 | int setnx(const char *key, const char *val); 310 | int setnx_printf(const char *format, ...); 311 | 312 | /** 313 | * http://redis.io/commands 314 | * 315 | * 316 | * static int cr_incr(REDIS rhnd, int incr, int decr, const char *key, int *new_val) 317 | * credis_incr 318 | * credis_decr 319 | * credis_incrby 320 | * credis_decrby 321 | * 322 | * 323 | * cr_multikeybulkcommand 324 | * cr_multikeystorecommand 325 | * credis_mget 326 | * 327 | * Set multiple keys to multiple values 328 | * MSET key value [key value ...] 329 | */ 330 | 331 | int append(const char *key, const char *val); 332 | int append_printf(const char *format, ...); 333 | 334 | int substr( const char *key, int start, int end); 335 | 336 | int exists( const char *key); 337 | int exists_printf(const char *format, ...); 338 | 339 | int del( const char *key); 340 | int del_printf(const char *format, ...); 341 | 342 | int delete_keys( const char *key); 343 | int delete_keys_printf(const char *format, ...); 344 | 345 | int type( const char *key); 346 | 347 | int keys(const char *pattern); 348 | int keys_printf(const char *format, ...); 349 | 350 | int randomkey(); 351 | 352 | int rename( const char *key, const char *new_key_name); 353 | int rename_printf(const char *format, ...); 354 | 355 | int renamenx( const char *key, const char *new_key_name); 356 | int renamenx_printf(const char *format, ...); 357 | 358 | /** 359 | * Return the number of keys in the selected database 360 | */ 361 | int dbsize(); 362 | 363 | int expire( const char *key, int secs); 364 | int expire_printf(const char *format, ...); 365 | 366 | 367 | int flushall(void); 368 | 369 | int sadd(const char *key, const char *member); 370 | int sadd_printf(const char *format, ...); 371 | 372 | int srem(const char *key, const char *member); 373 | int srem_printf(const char *format, ...); 374 | 375 | int smembers(const char *key); 376 | int smembers_printf(const char *format, ...); 377 | 378 | int scard(const char *key); 379 | int scard_printf(const char *format, ...); 380 | 381 | int lpush(const char *key, const char *member); 382 | int lpush_printf(const char *format, ...); 383 | 384 | int rpush(const char *key, const char *member); 385 | int rpush_printf(const char *format, ...); 386 | 387 | int ltrim(const char *key, int start_pos, int count_elem); 388 | int ltrim_printf(const char *format, ...); 389 | 390 | int lpop(const char *key); 391 | int lpop_printf(const char *format, ...); 392 | 393 | int rpop(const char *key); 394 | int rpop_printf(const char *format, ...); 395 | 396 | int llen(const char *key); 397 | int llen_printf(const char *format, ...); 398 | 399 | int lrem(const char *key, int n,const char* val); 400 | int lrem_printf(const char *format, ...); 401 | 402 | int lrange(const char *key, int start, int stop); 403 | int lrange_printf(const char *format, ...); 404 | 405 | 406 | /** 407 | * Returns the remaining time to live of a key that has a timeout. 408 | * @param key 409 | * @return 410 | */ 411 | int ttl( const char *key); 412 | int ttl_printf(const char *format, ...); 413 | 414 | 415 | int getRedisVersion(); 416 | 417 | /** 418 | * 419 | * @param TimeOut 420 | */ 421 | void setTimeout( int TimeOut); 422 | 423 | /** 424 | * Закрывает соединение 425 | */ 426 | void redis_close(); 427 | 428 | /** 429 | * Выдаётся указатьель на внутриний буфер чтения/записи ссылка потеряет актуальность при вызове любой функции на получение или запись данных. 430 | * Или по указаному адресу будут уже другие данные либо мусор. 431 | */ 432 | char* getData() const; 433 | char* getData(int i) const; 434 | 435 | /** 436 | * Возвращает количество пришедших данных в ответе. 437 | * Для списка это колво элементов для остальных типов это колво байт. 438 | */ 439 | int getDataSize() const; 440 | 441 | void setBufferSize(int size); 442 | int getBufferSize(); 443 | 444 | void setMaxBufferSize(int size); 445 | int getMaxBufferSize(); 446 | 447 | /** 448 | * Выбор бызы данных 449 | * @param index 450 | * @see http://redis.io/commands/select 451 | */ 452 | int selectDB(int index); 453 | 454 | int getError(); 455 | 456 | int redis_raw_send(char recvtype, const char *buffer); 457 | protected: 458 | 459 | char* lastAuthPw = NULL; 460 | int lastSelectDBIndex = 0; 461 | 462 | int reconect( ); 463 | 464 | 465 | int read_select(int fd, int timeout ) const; 466 | 467 | int wright_select(int fd, int timeout ) const; 468 | 469 | /** 470 | * Отправляет запрос редису 471 | * @param recvtype тип ожидаемого результата 472 | * @param format Строка запроса 473 | * @param ... 474 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 475 | */ 476 | int redis_send(char recvtype, const char *format, ...); 477 | 478 | /** 479 | * Отправляет данные 480 | * @param buf 481 | * @return 482 | */ 483 | int send_data( const char *buf ) const; 484 | 485 | }; 486 | 487 | 488 | 489 | #endif /* SIMPLEREDISCLIENT_H */ 490 | 491 | -------------------------------------------------------------------------------- /for-redis-2.6/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "SimpleRedisClient.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | SimpleRedisClient rc; 8 | 9 | rc.setHost("127.0.0.1"); 10 | rc.auth("home"); 11 | rc.LogLevel(0); 12 | 13 | if(!rc) 14 | { 15 | printf("Соединение с redis не установлено\n"); 16 | return -1; 17 | } 18 | 19 | rc = "MYKEY my-value-tester"; 20 | if(rc["MYKEY"]) 21 | { 22 | printf("MYKEY == [%d][%s]\n", (int)rc, (char*)rc); 23 | } 24 | 25 | printf("-------------------\n"); 26 | rc.sadd_printf("%s %d", "MY_SET", 123); 27 | rc.sadd_printf("%s %d", "MY_SET", 14); 28 | 29 | rc.smembers("MY_SET"); 30 | 31 | if(rc.getMultiBulkDataAmount()) 32 | { 33 | for(int i =0; i< rc.getMultiBulkDataAmount(); i++ ) 34 | { 35 | printf("Answer[%d]->%s\n", i, rc.getData(i)); 36 | } 37 | } 38 | 39 | rc = "MYKEY1 my-value-tester"; 40 | rc = "MYKEY2 my-value-tester"; 41 | 42 | rc.delete_keys("MY*"); 43 | 44 | rc.redis_close(); 45 | } -------------------------------------------------------------------------------- /for-redis-2.8/README.md: -------------------------------------------------------------------------------- 1 |

Клиент для работы с редисом версии 2.8

2 | 3 | 4 | This client tested only on Ubuntu, Debian, CentOS. (Этот клиент тестировался только под Ubuntu, Debian, CentOS) 5 | 6 | 7 |

Тестировался для redis версии 2.8

8 |

В разных версиях redis имеются отличия в протоколе, чтоб не усложнять код и не плодить баги для каждой версии redis свой клинт.

9 | 10 |

Последние изменения

11 |

12 |

    13 |
  • Добавлена поддержка redis версии 2.8
  • 14 |
  • Автоматически переподключается при потере соединения
  • 15 |
  • Добавлены некоторые функции от redis такие как select, dbsize и другие
  • 16 |
  • Поправлены баги работы с сетью
  • 17 |
18 |

19 | 20 |
21 | int main(int argc, char *argv[])
22 | {
23 |     SimpleRedisClient rc;
24 |   
25 |     rc.setHost(REDIS_HOST);
26 |     rc.auth(REDIS_PW);
27 |     rc.LogLevel(0);
28 | 
29 |     if(!rc)
30 |     {
31 |         printf("Соединение с redis не установлено\n");
32 |         return -1;
33 |     }
34 |     
35 |     rc = "MYKEY my-value-tester";
36 |     if(rc["MYKEY"])
37 |     {
38 |         printf("MYKEY == [%d][%s]\n", (int)rc, (char*)rc);
39 |     }
40 |   
41 |     printf("-------------------\n");
42 |     rc.sadd_printf("%s %d", "MY_SET", 123);
43 |     rc.sadd_printf("%s %d", "MY_SET", 14);
44 | 
45 |     rc.smembers("MY_SET");
46 | 
47 |     if(rc.getMultiBulkDataAmount())
48 |     {
49 |         for(int i =0; i< rc.getMultiBulkDataAmount(); i++ )
50 |         {
51 |             printf("Answer[%d]->%s\n", i, rc.getData(i));
52 |         }
53 |     }
54 | 
55 |     rc = "MYKEY1 my-value-tester";
56 |     rc = "MYKEY2 my-value-tester";
57 | 
58 |     rc.delete_keys("MY*");
59 |      
60 |     rc.redis_close();
61 | }
62 | 
63 | 64 | -------------------------------------------------------------------------------- /for-redis-2.8/SimpleRedisClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SimpleRedisClient.cpp 3 | * Author: victor 4 | * 5 | * Created on 10 Август 2013 г., 22:26 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | 38 | #include "SimpleRedisClient.h" 39 | 40 | #define debugLine printf("\n%s:%d\n", __FILE__, __LINE__) 41 | 42 | 43 | static void full_write(int fd, const char *buf, size_t len) 44 | { 45 | while (len > 0) { 46 | ssize_t ret = write(fd, buf, len); 47 | 48 | if ((ret == -1) && (errno != EINTR)) 49 | break; 50 | 51 | buf += (size_t) ret; 52 | len -= (size_t) ret; 53 | } 54 | } 55 | 56 | void print_rcBacktrace(const char* reason) 57 | { 58 | static const char start[] = "\x1b[1;31m------------ RC-BACKTRACE ------------\x1b[0m\n"; 59 | static const char end[] = "\x1b[1;31m--------------------------------------\x1b[0m\n"; 60 | 61 | void *bt[1024]; 62 | int bt_size; 63 | char **bt_syms; 64 | int i; 65 | 66 | bt_size = backtrace(bt, 1024); 67 | bt_syms = backtrace_symbols(bt, bt_size); 68 | full_write(STDERR_FILENO, start, strlen(start)); 69 | full_write(STDERR_FILENO, reason, strlen(reason)); 70 | for (i = 1; i < bt_size; i++) { 71 | size_t len = strlen(bt_syms[i]); 72 | full_write(STDERR_FILENO, bt_syms[i], len); 73 | full_write(STDERR_FILENO, "\n", 1); 74 | } 75 | full_write(STDERR_FILENO, end, strlen(end)); 76 | free(bt_syms); 77 | } 78 | 79 | /** 80 | * Читает целое число из строки, если ошибка то вернёт -1 81 | * @param buffer Строка 82 | * @param delimiter Конец для числа 83 | * @param delta Количество символов занятое числом и разделителем 84 | * @return 85 | */ 86 | int read_int(const char* buffer,char delimiter,int* delta) 87 | { 88 | const char* p = buffer; 89 | int len = 0; 90 | int d = 0; 91 | 92 | while(*p == '0' ) 93 | { 94 | (*delta)++; 95 | p++; 96 | //return 0; 97 | } 98 | 99 | while(*p != delimiter) 100 | { 101 | if(*p > '9' || *p < '0') 102 | { 103 | return -1; 104 | } 105 | 106 | len = (len*10)+(*p - '0'); 107 | p++; 108 | (*delta)++; 109 | d++; 110 | 111 | if(d > 9) 112 | { 113 | return -1; 114 | } 115 | } 116 | return len; 117 | } 118 | 119 | int read_int(const char* buffer,char delimiter) 120 | { 121 | const char* p = buffer; 122 | int len = 0; 123 | int delta = 0; 124 | 125 | while(*p == '0' ) 126 | { 127 | p++; 128 | } 129 | 130 | while(*p != delimiter) 131 | { 132 | if(*p > '9' || *p < '0') 133 | { 134 | return -1; 135 | } 136 | 137 | len = (len*10)+(*p - '0'); 138 | p++; 139 | delta++; 140 | if(delta > 9) 141 | { 142 | return -1; 143 | } 144 | } 145 | 146 | return len; 147 | } 148 | 149 | int read_int(const char* buffer, int* delta) 150 | { 151 | const char* p = buffer; 152 | int len = 0; 153 | int d = 0; 154 | 155 | while(*p == '0' ) 156 | { 157 | (*delta)++; 158 | p++; 159 | //return 0; 160 | } 161 | 162 | while(1) 163 | { 164 | if(*p > '9' || *p < '0') 165 | { 166 | return len; 167 | } 168 | 169 | len = (len*10)+(*p - '0'); 170 | p++; 171 | (*delta)++; 172 | d++; 173 | 174 | if(d > 9) 175 | { 176 | return -1; 177 | } 178 | } 179 | return len; 180 | } 181 | /** 182 | * Читает целое число из строки, если ошибка то вернёт -1 183 | * @param buffer Строка 184 | * @param delimiter Конец для числа 185 | * @param delta Количество символов занятое числом и разделителем 186 | * @return 187 | */ 188 | long read_long(const char* buffer,char delimiter,int* delta) 189 | { 190 | const char* p = buffer; 191 | int len = 0; 192 | int d = 0; 193 | 194 | while(*p == '0' ) 195 | { 196 | (*delta)++; 197 | p++; 198 | //return 0; 199 | } 200 | 201 | while(*p != delimiter) 202 | { 203 | if(*p > '9' || *p < '0') 204 | { 205 | return -1; 206 | } 207 | 208 | len = (len*10)+(*p - '0'); 209 | p++; 210 | (*delta)++; 211 | d++; 212 | 213 | if(d > 18) 214 | { 215 | return -1; 216 | } 217 | } 218 | return len; 219 | } 220 | 221 | long read_long(const char* buffer,char delimiter) 222 | { 223 | const char* p = buffer; 224 | int len = 0; 225 | int delta = 0; 226 | 227 | while(*p == '0' ) 228 | { 229 | p++; 230 | } 231 | 232 | while(*p != delimiter) 233 | { 234 | if(*p > '9' || *p < '0') 235 | { 236 | return -1; 237 | } 238 | 239 | len = (len*10)+(*p - '0'); 240 | p++; 241 | delta++; 242 | if(delta > 18) 243 | { 244 | return -1; 245 | } 246 | } 247 | 248 | return len; 249 | } 250 | 251 | long read_long(const char* buffer, int* delta) 252 | { 253 | const char* p = buffer; 254 | int len = 0; 255 | int d = 0; 256 | 257 | while(*p == '0' ) 258 | { 259 | (*delta)++; 260 | p++; 261 | //return 0; 262 | } 263 | 264 | while(1) 265 | { 266 | if(*p > '9' || *p < '0') 267 | { 268 | return len; 269 | } 270 | 271 | len = (len*10)+(*p - '0'); 272 | p++; 273 | (*delta)++; 274 | d++; 275 | 276 | if(d > 18) 277 | { 278 | return -1; 279 | } 280 | } 281 | return len; 282 | } 283 | 284 | #define REDIS_PRINTF_MACRO_CODE(type, comand) va_list ap;\ 285 | va_start(ap, format);\ 286 | bzero(buf, buffer_size);\ 287 | int rc = vsnprintf(buf, buffer_size, format, ap);\ 288 | va_end(ap);\ 289 | if( rc >= buffer_size ) return RC_ERR_BUFFER_OVERFLOW;\ 290 | if(rc < 0) return RC_ERR_DATA_FORMAT;\ 291 | rc = redis_send( type, "%s %s\r\n", comand, buf);\ 292 | return rc;\ 293 | 294 | 295 | SimpleRedisClient::SimpleRedisClient() 296 | { 297 | setBufferSize(2048); 298 | } 299 | 300 | int SimpleRedisClient::getBufferSize() 301 | { 302 | return buffer_size; 303 | } 304 | 305 | 306 | void SimpleRedisClient::setMaxBufferSize(int size) 307 | { 308 | max_buffer_size = size; 309 | } 310 | 311 | int SimpleRedisClient::getMaxBufferSize() 312 | { 313 | return max_buffer_size; 314 | } 315 | 316 | void SimpleRedisClient::setBufferSize(int size) 317 | { 318 | if(buffer != 0) 319 | { 320 | delete[] buffer; 321 | delete[] buf; 322 | } 323 | 324 | buffer_size = size; 325 | buffer = new char[buffer_size]; 326 | buf = new char[buffer_size]; 327 | } 328 | 329 | SimpleRedisClient::~SimpleRedisClient() 330 | { 331 | redis_close(); 332 | 333 | 334 | if(buffer != NULL) 335 | { 336 | delete[] buffer; 337 | } 338 | 339 | if(buf != NULL) 340 | { 341 | delete[] buf; 342 | } 343 | 344 | buffer_size = 0; 345 | 346 | if(host != 0) 347 | { 348 | delete[] host; 349 | } 350 | 351 | if(lastAuthPw != NULL) 352 | { 353 | delete[] lastAuthPw; 354 | } 355 | } 356 | 357 | /* 358 | * Returns: 359 | * >0 Колво байт 360 | * 0 Соединение закрыто 361 | * -1 error 362 | * -2 timeout 363 | **/ 364 | int SimpleRedisClient::read_select(int fd, int timeout ) const 365 | { 366 | struct timeval tv; 367 | fd_set fds; 368 | 369 | tv.tv_sec = timeout / 1000; 370 | tv.tv_usec = (timeout % 1000)*1000; 371 | 372 | FD_ZERO(&fds); 373 | FD_SET(fd, &fds); 374 | 375 | return select(fd + 1, &fds, NULL, NULL, &tv); 376 | } 377 | 378 | /* 379 | * Returns: 380 | * >0 Колво байт 381 | * 0 Соединение закрыто 382 | * -1 error 383 | * -2 timeout 384 | **/ 385 | int SimpleRedisClient::wright_select(int fd, int timeout ) const 386 | { 387 | struct timeval tv; 388 | fd_set fds; 389 | 390 | tv.tv_sec = timeout / 1000; 391 | tv.tv_usec = (timeout % 1000)*1000; 392 | 393 | FD_ZERO(&fds); 394 | FD_SET(fd, &fds); 395 | 396 | return select(fd+1, NULL, &fds, NULL, &tv); 397 | } 398 | 399 | void SimpleRedisClient::LogLevel(int l) 400 | { 401 | debug = l; 402 | } 403 | 404 | int SimpleRedisClient::LogLevel(void) 405 | { 406 | return debug; 407 | } 408 | 409 | int SimpleRedisClient::getError(void) 410 | { 411 | return last_error; 412 | } 413 | 414 | int SimpleRedisClient::redis_raw_send(char recvtype,const char *dataCommand) 415 | { 416 | int rc = send_data(dataCommand); 417 | 418 | if (rc < 0) 419 | { 420 | print_rcBacktrace("Данные не отправлены [RC_ERR_SEND]"); 421 | reconect(); 422 | return RC_ERR_SEND; 423 | } 424 | 425 | if (rc != (int) strlen(dataCommand)) 426 | { 427 | print_rcBacktrace("Ответ не получен [RC_ERR_TIMEOUT]"); 428 | reconect(); 429 | return RC_ERR_TIMEOUT; 430 | } 431 | 432 | 433 | bzero(buffer,buffer_size); 434 | rc = read_select(fd, timeout); 435 | 436 | if(debug) printf("REDIS read_select=%d\n", rc); 437 | if (rc > 0) 438 | { 439 | 440 | int offset = 0; 441 | do{ 442 | rc = recv(fd, buffer + offset, buffer_size - offset, 0); 443 | 444 | if(rc < 0) 445 | { 446 | return CR_ERR_RECV; 447 | } 448 | 449 | if(rc >= buffer_size - offset && buffer_size * 2 > max_buffer_size) 450 | { 451 | char nullbuf[1000]; 452 | int r = 0; 453 | while( (r = recv(fd, nullbuf, 1000, 0)) >= 0) 454 | { 455 | if(debug) printf("REDIS read %d byte\n", r); 456 | } 457 | 458 | last_error = RC_ERR_DATA_BUFFER_OVERFLOW; 459 | break; 460 | } 461 | else if(rc >= buffer_size - offset && buffer_size * 2 < max_buffer_size) 462 | { 463 | if(debug) printf("REDIS Удвоение размера буфера до %d\t[rc=%d, buffer_size=%d, offset=%d]\n",buffer_size *2, rc, buffer_size, offset); 464 | 465 | int last_buffer_size = buffer_size; 466 | char* tbuf = buffer; 467 | 468 | buffer_size *= 2; 469 | buffer = new char[buffer_size]; 470 | 471 | delete buf; 472 | buf = new char[buffer_size]; 473 | 474 | memcpy(buffer, tbuf, last_buffer_size); 475 | offset = last_buffer_size; 476 | } 477 | else 478 | { 479 | break; 480 | } 481 | 482 | }while(1); 483 | if(debug >= RC_LOG_DEBUG) printf("REDIS BUF: recv:%d buffer[%s]",rc, buffer); 484 | 485 | char prefix = buffer[0]; 486 | if (recvtype != RC_ANY && prefix != recvtype && prefix != RC_ERROR) 487 | { 488 | printf("\x1b[31m[fd=%d]REDIS RC_ERR_PROTOCOL[%c]:%s\x1b[0m\n",fd, recvtype, buffer); 489 | print_rcBacktrace(buffer); 490 | return RC_ERR_PROTOCOL; 491 | } 492 | 493 | char *p; 494 | int len = 0; 495 | switch (prefix) 496 | { 497 | case RC_ERROR: 498 | printf("\x1b[31mREDIS[fd=%d] RC_ERROR:%s\x1b[0m\n",fd,buffer); 499 | data = buffer; 500 | data_size = rc; 501 | print_rcBacktrace(buffer); 502 | return -rc; 503 | case RC_INLINE: 504 | if(debug) printf("\x1b[33mREDIS[fd=%d] RC_INLINE:%s\x1b[0m\n", fd,buffer); 505 | data_size = strlen(buffer+1)-2; 506 | data = buffer+1; 507 | data[data_size] = 0; 508 | return rc; 509 | case RC_INT: 510 | if(debug) printf("\x1b[33mREDIS[fd=%d] RC_INT:%s\x1b[0m\n",fd, buffer); 511 | data = buffer+1; 512 | data_size = rc; 513 | return rc; 514 | case RC_BULK: 515 | if(debug) printf("\x1b[33mREDIS[fd=%d] RC_BULK:%s\x1b[0m\n",fd, buffer); 516 | 517 | p = buffer; 518 | p++; 519 | 520 | if(*p == '-') 521 | { 522 | data = 0; 523 | data_size = -1; 524 | return rc; 525 | } 526 | 527 | while(*p != '\r') { 528 | len = (len*10)+(*p - '0'); 529 | p++; 530 | } 531 | 532 | /* Now p points at '\r', and the len is in bulk_len. */ 533 | if(debug > 3) printf("%d\n", len); 534 | 535 | data = p+2; 536 | data_size = len; 537 | data[data_size] = 0; 538 | 539 | return rc; 540 | case RC_MULTIBULK: 541 | if(debug) printf("\x1b[33mREDIS[fd=%d] RC_MULTIBULK[Len=%d]:%s\x1b[0m\n", fd, rc, buffer); 542 | data = buffer; 543 | 544 | p = buffer; 545 | p++; 546 | int delta = 0; 547 | multibulk_arg = read_int(p, &delta); 548 | if(multibulk_arg < 1) 549 | { 550 | data = 0; 551 | data_size = -1; 552 | if(debug > 5) printf("\x1b[33mREDIS RC_MULTIBULK data_size = 0\x1b[0m\n"); 553 | return rc; 554 | } 555 | 556 | data_size = multibulk_arg; 557 | 558 | answer_multibulk = new char*[multibulk_arg]; 559 | 560 | p+= delta + 3; 561 | 562 | for(int i =0; i< multibulk_arg; i++) 563 | { 564 | if( buffer_size - 10 < p - buffer) 565 | { 566 | multibulk_arg = i-1; 567 | data_size = i - 1; 568 | if(debug) printf("\x1b[33mREDIS Выход по приближению к концу буфера [p=%d|multibulk_arg=%d]\x1b[0m\n", (int)(p - buffer), multibulk_arg); 569 | last_error = RC_ERR_DATA_BUFFER_OVERFLOW; 570 | return rc; 571 | } 572 | 573 | len = 0; 574 | while(*p != '\r') { 575 | len = (len*10)+(*p - '0'); 576 | p++; 577 | } 578 | 579 | p+=2; 580 | answer_multibulk[i] = p; 581 | 582 | p+= len; 583 | 584 | if( buffer_size - 1 < p - buffer ) 585 | { 586 | multibulk_arg = i-1; 587 | data_size = i - 1; 588 | if(debug) printf("\x1b[33mREDIS Выход по приближению к концу буфера [p=%d|multibulk_arg=%d]\x1b[0m\n", (int)(p - buffer), multibulk_arg); 589 | last_error = RC_ERR_DATA_BUFFER_OVERFLOW; 590 | return rc; 591 | } 592 | 593 | 594 | *p = 0; 595 | p+= 3; 596 | } 597 | 598 | return rc; 599 | } 600 | 601 | return rc; 602 | } 603 | else if (rc == 0) 604 | { 605 | print_rcBacktrace("Соединение закрыто [RC_ERR_CONECTION_CLOSE]"); 606 | reconect(); 607 | return RC_ERR_CONECTION_CLOSE; // Соединение закрыто 608 | } 609 | else 610 | { 611 | print_rcBacktrace("Не пришли данные от redis[RC_ERR]"); 612 | return RC_ERR; // error 613 | } 614 | } 615 | 616 | int SimpleRedisClient::redis_send(char recvtype, const char *format, ...) 617 | { 618 | if(fd <= 0) 619 | { 620 | if(redis_conect() < 0) 621 | { 622 | return RC_ERR; 623 | } 624 | } 625 | 626 | data = 0; 627 | data_size = 0; 628 | 629 | if(answer_multibulk != 0) 630 | { 631 | delete[] answer_multibulk; 632 | } 633 | multibulk_arg = -1; 634 | answer_multibulk = 0; 635 | 636 | va_list ap; 637 | va_start(ap, format); 638 | 639 | bzero(buffer,buffer_size); 640 | int rc = vsnprintf(buffer, buffer_size, format, ap); 641 | va_end(ap); 642 | 643 | if( rc < 0 ) 644 | { 645 | return RC_ERR_DATA_FORMAT; 646 | } 647 | 648 | if( rc >= buffer_size ) 649 | { 650 | return RC_ERR_BUFFER_OVERFLOW; // Не хватило буфера 651 | } 652 | 653 | if(debug > 3 ) printf("SEND:%s",buffer); 654 | 655 | return redis_raw_send(recvtype, buffer); 656 | } 657 | 658 | /** 659 | * Отправляет данные 660 | * @param buf 661 | * @return 662 | */ 663 | int SimpleRedisClient::send_data( const char *buf ) const 664 | { 665 | fd_set fds; 666 | struct timeval tv; 667 | int sent = 0; 668 | 669 | /* NOTE: On Linux, select() modifies timeout to reflect the amount 670 | * of time not slept, on other systems it is likely not the same */ 671 | tv.tv_sec = timeout / 1000; 672 | tv.tv_usec = (timeout % 1000)*1000; 673 | 674 | int tosend = strlen(buf); // При отправке бинарных данных возможны баги. 675 | 676 | while (sent < tosend) 677 | { 678 | FD_ZERO(&fds); 679 | FD_SET(fd, &fds); 680 | 681 | int rc = select(fd + 1, NULL, &fds, NULL, &tv); 682 | 683 | if (rc > 0) 684 | { 685 | rc = send(fd, buf + sent, tosend - sent, 0); 686 | if (rc < 0) 687 | { 688 | return -1; 689 | } 690 | sent += rc; 691 | } 692 | else if (rc == 0) /* timeout */ 693 | { 694 | break; 695 | } 696 | else 697 | { 698 | return -1; 699 | } 700 | } 701 | 702 | return sent; 703 | } 704 | 705 | /** 706 | * public: 707 | */ 708 | 709 | void SimpleRedisClient::setPort(int Port) 710 | { 711 | port = Port; 712 | } 713 | 714 | void SimpleRedisClient::setHost(const char* Host) 715 | { 716 | if(host != 0) 717 | { 718 | delete host; 719 | } 720 | 721 | host = new char[64]; 722 | bzero(host, 64); 723 | memcpy(host,Host,strlen(Host)); 724 | } 725 | 726 | /** 727 | * Соединение с редисом. 728 | */ 729 | int SimpleRedisClient::redis_conect(const char* Host,int Port) 730 | { 731 | setPort(Port); 732 | setHost(Host); 733 | return redis_conect(); 734 | } 735 | 736 | int SimpleRedisClient::redis_conect(const char* Host,int Port, int TimeOut) 737 | { 738 | setPort(Port); 739 | setHost(Host); 740 | setTimeout(TimeOut); 741 | return redis_conect(); 742 | } 743 | 744 | int SimpleRedisClient::reconect() 745 | { 746 | 747 | if(debug > 1) printf("\x1b[31mredis reconect[%s:%d]\x1b[0m\n", host, port); 748 | 749 | redis_close(); 750 | if(!redis_conect()) 751 | { 752 | return false; 753 | } 754 | 755 | if(lastAuthPw != NULL ) 756 | { 757 | printf("\x1b[31mredis reconect lastAuthPw=%s\x1b[0m\n", lastAuthPw); 758 | if(redis_send( RC_INLINE, "AUTH %s\r\n", lastAuthPw)) 759 | { 760 | return false; 761 | } 762 | } 763 | 764 | if(lastSelectDBIndex != 0 ) 765 | { 766 | if( !selectDB(lastSelectDBIndex) ) 767 | { 768 | return false; 769 | } 770 | } 771 | 772 | return true; 773 | } 774 | 775 | int SimpleRedisClient::redis_conect() 776 | { 777 | if(host == 0) 778 | { 779 | setHost("127.0.0.1"); 780 | } 781 | 782 | if(debug >= RC_LOG_LOG) printf("\x1b[32mredis host:%s %d\x1b[0m\n", host, port); 783 | 784 | int rc; 785 | struct sockaddr_in sa; 786 | bzero(&sa, sizeof(sa)); 787 | 788 | sa.sin_family = AF_INET; 789 | sa.sin_port = htons(port); 790 | 791 | if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1 || setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&yes, sizeof(yes)) == -1 || setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&yes, sizeof(yes)) == -1) 792 | { 793 | printf("open error %d\n", fd); 794 | } 795 | 796 | struct addrinfo hints, *info = NULL; 797 | bzero(&hints, sizeof(hints)); 798 | 799 | if (inet_aton(host, &sa.sin_addr) == 0) 800 | { 801 | hints.ai_family = AF_INET; 802 | hints.ai_socktype = SOCK_STREAM; 803 | int err = getaddrinfo(host, NULL, &hints, &info); 804 | if (err) 805 | { 806 | printf("\x1b[31mgetaddrinfo error: %s [%s]\x1b[0m\n", gai_strerror(err), host); 807 | print_rcBacktrace("\x1b[31mgetaddrinfo error\x1b[0m\n"); 808 | return RC_ERR; 809 | } 810 | 811 | memcpy(&sa.sin_addr.s_addr, &(info->ai_addr->sa_data[2]), sizeof(in_addr_t)); 812 | freeaddrinfo(info); 813 | } 814 | 815 | int flags = fcntl(fd, F_GETFL); 816 | if ((rc = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) < 0) 817 | { 818 | printf("\x1b[31mSetting socket non-blocking failed with: %d\x1b[0m\n", rc); 819 | print_rcBacktrace("\x1b[31mSetting socket non-blocking failed\x1b[0m\n"); 820 | return RC_ERR; 821 | } 822 | 823 | if( connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != 0) 824 | { 825 | if (errno != EINPROGRESS) 826 | { 827 | print_rcBacktrace("\x1b[31mconnect error\x1b[0m\n"); 828 | close(fd); 829 | fd = 0; 830 | return RC_ERR; 831 | } 832 | 833 | if (wright_select(fd, timeout) > 0) 834 | { 835 | int err = 0; 836 | unsigned int len = sizeof(err); 837 | if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == -1 || err) 838 | { 839 | print_rcBacktrace("\x1b[31mgetsockopt error\x1b[0m\n"); 840 | close(fd); 841 | fd = 0; 842 | return RC_ERR; 843 | } 844 | } 845 | else /* timeout or select error */ 846 | { 847 | print_rcBacktrace("\x1b[31mtimeout or select error\x1b[0m\n"); 848 | close(fd); 849 | fd = 0; 850 | return RC_ERR_TIMEOUT; 851 | } 852 | } 853 | 854 | if(debug > RC_LOG_DEBUG) printf("open ok %d\n", fd); 855 | return fd; 856 | } 857 | 858 | char** SimpleRedisClient::getMultiBulkData() 859 | { 860 | return answer_multibulk; 861 | } 862 | 863 | /** 864 | * Вернёт количество ответов. Или -1 если последняя операция вернула что либо кроме множества ответов. 865 | * @return 866 | */ 867 | int SimpleRedisClient::getMultiBulkDataAmount() 868 | { 869 | return multibulk_arg; 870 | } 871 | 872 | /** 873 | * Работает только после запроса данных которые возвращаются как множество ответов 874 | * @param i Номер ответа в множестве отвкетов 875 | * @return Вернёт ноль в случаи ошибки или указатель на данные 876 | */ 877 | char* SimpleRedisClient::getData(int i) const 878 | { 879 | if(multibulk_arg > i) 880 | { 881 | return answer_multibulk[i]; 882 | } 883 | return 0; 884 | } 885 | 886 | /** 887 | * Выбор бызы данных 888 | * @param index 889 | * @see http://redis.io/commands/select 890 | */ 891 | int SimpleRedisClient::selectDB(int index) 892 | { 893 | lastSelectDBIndex = index; 894 | return redis_send(RC_INLINE, "SELECT %d\r\n", index); 895 | } 896 | 897 | 898 | /** 899 | * Возвращает все члены множества, сохранённого в указанном ключе. Эта команда - просто упрощённый синтаксис для SINTER. 900 | * SMEMBERS key 901 | * Время выполнения: O(N). 902 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-smembers 903 | * @see http://redis.io/commands/smembers 904 | * @param key 905 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 906 | */ 907 | int SimpleRedisClient::smembers(const char *key) 908 | { 909 | return redis_send(RC_MULTIBULK, "SMEMBERS '%s'\r\n", key); 910 | } 911 | 912 | /** 913 | * Возвращает все члены множества, сохранённого в указанном ключе. Эта команда - просто упрощённый синтаксис для SINTER. 914 | * SMEMBERS key 915 | * Время выполнения: O(N). 916 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-smembers 917 | * @see http://redis.io/commands/smembers 918 | * @param key 919 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 920 | */ 921 | int SimpleRedisClient::smembers_printf(const char *format, ...) 922 | { 923 | REDIS_PRINTF_MACRO_CODE(RC_MULTIBULK, "SMEMBERS") 924 | } 925 | 926 | /** 927 | * Returns the set cardinality (number of elements) of the set stored at key. 928 | * @see http://redis.io/commands/scard 929 | * @param key 930 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 931 | */ 932 | int SimpleRedisClient::scard(const char *key) 933 | { 934 | return redis_send(RC_INT, "SCARD '%s'\r\n", key); 935 | } 936 | 937 | /** 938 | * Returns the set cardinality (number of elements) of the set stored at key. 939 | * @see http://redis.io/commands/scard 940 | * @param key 941 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 942 | */ 943 | int SimpleRedisClient::scard_printf(const char *format, ...) 944 | { 945 | REDIS_PRINTF_MACRO_CODE(RC_INT, "SCARD") 946 | } 947 | 948 | /** 949 | * Ни ключь ни значение не должны содержать "\r\n" 950 | * @param key 951 | * @param val 952 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 953 | */ 954 | int SimpleRedisClient::set(const char *key, const char *val) 955 | { 956 | return redis_send( RC_INLINE, "SET '%s' '%s'\r\n", key, val); 957 | } 958 | 959 | int SimpleRedisClient::set_printf(const char *format, ...) 960 | { 961 | REDIS_PRINTF_MACRO_CODE(RC_INLINE, "SET") 962 | } 963 | 964 | SimpleRedisClient& SimpleRedisClient::operator=(const char *key_val) 965 | { 966 | redis_send( RC_INLINE, "SET %s\r\n", key_val); 967 | return *this; 968 | } 969 | 970 | 971 | int SimpleRedisClient::setex(const char *key, const char *val, int seconds) 972 | { 973 | return redis_send(RC_INLINE, "SETEX '%s' %d '%s'\r\n",key, seconds, val); 974 | } 975 | 976 | int SimpleRedisClient::setex_printf(int seconds, const char *key, const char *format, ...) 977 | { 978 | va_list ap; 979 | va_start(ap, format); 980 | 981 | bzero(buf, buffer_size); 982 | int rc = vsnprintf(buf, buffer_size, format, ap); 983 | va_end(ap); 984 | 985 | if( rc >= buffer_size ) 986 | { 987 | return RC_ERR_BUFFER_OVERFLOW;; // Не хватило буфера 988 | } 989 | 990 | if(rc < 0) 991 | { 992 | return RC_ERR_DATA_FORMAT; 993 | } 994 | 995 | return redis_send(RC_INLINE, "SETEX '%s' %d '%s'\r\n",key, seconds, buf); 996 | } 997 | 998 | int SimpleRedisClient::setex_printf(const char *format, ...) 999 | { 1000 | REDIS_PRINTF_MACRO_CODE(RC_INLINE, "SETEX") 1001 | } 1002 | 1003 | 1004 | int SimpleRedisClient::get(const char *key) 1005 | { 1006 | return redis_send( RC_BULK, "GET '%s'\r\n", key); 1007 | } 1008 | 1009 | 1010 | int SimpleRedisClient::get_printf( const char *format, ...) 1011 | { 1012 | REDIS_PRINTF_MACRO_CODE(RC_BULK, "GET") 1013 | } 1014 | 1015 | /** 1016 | * Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members. 1017 | * An error is returned when the value stored at key is not a set. 1018 | * @see http://redis.io/commands/sadd 1019 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-sadd 1020 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1021 | */ 1022 | int SimpleRedisClient::sadd(const char *key, const char *member) 1023 | { 1024 | return redis_send(RC_INT, "SADD '%s' '%s'\r\n", key, member); 1025 | } 1026 | 1027 | /** 1028 | * Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members. 1029 | * An error is returned when the value stored at key is not a set. 1030 | * @see http://redis.io/commands/sadd 1031 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-sadd 1032 | * @param format 1033 | * @param ... Ключь Значение (через пробел, в значении нет пробелов) 1034 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1035 | */ 1036 | int SimpleRedisClient::sadd_printf(const char *format, ...) 1037 | { 1038 | REDIS_PRINTF_MACRO_CODE(RC_INT, "SADD") 1039 | } 1040 | 1041 | /** 1042 | * Remove the specified members from the set stored at key. 1043 | * Specified members that are not a member of this set are ignored. 1044 | * If key does not exist, it is treated as an empty set and this command returns 0. 1045 | * An error is returned when the value stored at key is not a set. 1046 | * 1047 | * @see http://redis.io/commands/srem 1048 | * @param key 1049 | * @param member 1050 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1051 | */ 1052 | int SimpleRedisClient::srem(const char *key, const char *member) 1053 | { 1054 | return redis_send(RC_INT, "SREM '%s' '%s'\r\n", key, member); 1055 | } 1056 | 1057 | /** 1058 | * Remove the specified members from the set stored at key. 1059 | * Specified members that are not a member of this set are ignored. If key does not exist, it is treated as an empty set and this command returns 0. 1060 | * An error is returned when the value stored at key is not a set. 1061 | * @see http://redis.io/commands/srem 1062 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-srem 1063 | * @param format 1064 | * @param ... Ключь Значение (через пробел, в значении нет пробелов) 1065 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1066 | */ 1067 | int SimpleRedisClient::srem_printf(const char *format, ...) 1068 | { 1069 | REDIS_PRINTF_MACRO_CODE(RC_INT, "SREM") 1070 | } 1071 | 1072 | 1073 | char* SimpleRedisClient::operator[] (const char *key) 1074 | { 1075 | redis_send( RC_BULK, "GET '%s'\r\n", key); 1076 | return getData(); 1077 | } 1078 | 1079 | SimpleRedisClient::operator char* () const 1080 | { 1081 | return getData(); 1082 | } 1083 | 1084 | /** 1085 | * @todo ЗАДОКУМЕНТИРОВАТЬ 1086 | * @return 1087 | */ 1088 | SimpleRedisClient::operator int () const 1089 | { 1090 | if(data_size < 1) 1091 | { 1092 | printf("SimpleRedisClient::operator int (%u) \n", data_size); 1093 | return data_size; 1094 | } 1095 | 1096 | if(getData() == 0) 1097 | { 1098 | printf("SimpleRedisClient::operator int (%u) \n", data_size); 1099 | return -1; 1100 | } 1101 | 1102 | int d = 0; 1103 | int r = read_int(getData(), &d); 1104 | 1105 | printf("SimpleRedisClient::operator int (%u|res=%d) \n", data_size, r); 1106 | 1107 | return r; 1108 | } 1109 | 1110 | /** 1111 | * @todo ЗАДОКУМЕНТИРОВАТЬ 1112 | * @return 1113 | */ 1114 | SimpleRedisClient::operator long () const 1115 | { 1116 | if(data_size < 1) 1117 | { 1118 | printf("SimpleRedisClient::operator long (%u) \n", data_size); 1119 | return data_size; 1120 | } 1121 | 1122 | if(getData() == 0) 1123 | { 1124 | printf("SimpleRedisClient::operator long (%u) \n", data_size); 1125 | return -1; 1126 | } 1127 | 1128 | int d = 0; 1129 | int r = read_long(getData(), &d); 1130 | 1131 | printf("SimpleRedisClient::operator long (%u|res=%d) \n", data_size, r); 1132 | 1133 | return r; 1134 | } 1135 | 1136 | int SimpleRedisClient::getset(const char *key, const char *set_val) 1137 | { 1138 | return redis_send( RC_BULK, "GETSET '%s' '%s'\r\n", key, set_val); 1139 | } 1140 | 1141 | int SimpleRedisClient::getset_printf(const char *format, ...) 1142 | { 1143 | REDIS_PRINTF_MACRO_CODE(RC_BULK, "GETSET") 1144 | } 1145 | 1146 | int SimpleRedisClient::ping() 1147 | { 1148 | return redis_send( RC_INLINE, "PING\r\n"); 1149 | } 1150 | 1151 | int SimpleRedisClient::echo(const char *message) 1152 | { 1153 | return redis_send( RC_BULK, "ECHO '%s'\r\n", message);; 1154 | } 1155 | 1156 | int SimpleRedisClient::quit() 1157 | { 1158 | return redis_send( RC_INLINE, "QUIT\r\n"); 1159 | } 1160 | 1161 | int SimpleRedisClient::auth(const char *password) 1162 | { 1163 | if(lastAuthPw != NULL) 1164 | { 1165 | delete[] lastAuthPw; 1166 | } 1167 | 1168 | int pwLen = strlen(password); 1169 | lastAuthPw = new char[pwLen+1]; 1170 | memcpy(lastAuthPw, password, pwLen); 1171 | lastAuthPw[pwLen] = 0; 1172 | 1173 | printf("\x1b[32mredis new lastAuthPw[%d]='%s'\x1b[0m\n", pwLen, lastAuthPw); 1174 | 1175 | return redis_send( RC_INLINE, "AUTH %s\r\n", password); 1176 | } 1177 | 1178 | 1179 | int SimpleRedisClient::getRedisVersion() 1180 | { 1181 | /* We can receive 2 version formats: x.yz and x.y.z, where x.yz was only used prior 1182 | * first 1.1.0 release(?), e.g. stable releases 1.02 and 1.2.6 */ 1183 | /* TODO check returned error string, "-ERR operation not permitted", to detect if 1184 | * server require password? */ 1185 | if (redis_send( RC_BULK, "INFO\r\n") == 0) 1186 | { 1187 | sscanf(buffer, "redis_version:%9d.%9d.%9d\r\n", &version_major, &version_minor, &version_patch); 1188 | return version_major; 1189 | } 1190 | 1191 | return 0; 1192 | } 1193 | 1194 | 1195 | int SimpleRedisClient::setnx(const char *key, const char *val) 1196 | { 1197 | return redis_send( RC_INT, "SETNX '%s' '%s'\r\n", key, val); 1198 | } 1199 | 1200 | int SimpleRedisClient::setnx_printf(const char *format, ...) 1201 | { 1202 | REDIS_PRINTF_MACRO_CODE(RC_INT, "SETNX") 1203 | } 1204 | 1205 | int SimpleRedisClient::append(const char *key, const char *val) 1206 | { 1207 | return redis_send(RC_INT, "APPEND '%s' '%s'\r\n", key, val); 1208 | } 1209 | 1210 | int SimpleRedisClient::append_printf(const char *format, ...) 1211 | { 1212 | REDIS_PRINTF_MACRO_CODE(RC_INT, "APPEND") 1213 | } 1214 | 1215 | int SimpleRedisClient::substr( const char *key, int start, int end) 1216 | { 1217 | return redis_send(RC_BULK, "SUBSTR '%s' %d %d\r\n", key, start, end); 1218 | } 1219 | 1220 | int SimpleRedisClient::exists( const char *key) 1221 | { 1222 | return redis_send( RC_INT, "EXISTS '%s'\r\n", key); 1223 | } 1224 | 1225 | int SimpleRedisClient::exists_printf(const char *format, ...) 1226 | { 1227 | REDIS_PRINTF_MACRO_CODE(RC_INT, "EXISTS") 1228 | } 1229 | 1230 | 1231 | /** 1232 | * Время выполнения: O(1) 1233 | * Удаление указанных ключей. Если переданный ключ не существует, операция для него не выполняется. Команда возвращает количество удалённых ключей. 1234 | * @see http://pyha.ru/wiki/index.php?title=Redis:cmd-del 1235 | * @see http://redis.io/commands/del 1236 | * @param key 1237 | * @return 1238 | */ 1239 | int SimpleRedisClient::del( const char *key) 1240 | { 1241 | return redis_send( RC_INT, "DEL '%s'\r\n", key); 1242 | } 1243 | 1244 | int SimpleRedisClient::del_printf(const char *format, ...) 1245 | { 1246 | REDIS_PRINTF_MACRO_CODE(RC_INT, "DEL") 1247 | } 1248 | 1249 | /** 1250 | * Удаляет все найденые ключи, тоесть ищет их командой keys и удаляет каждый найденый ключь. 1251 | * @param key 1252 | * @return Вернёт -1 или количество удалёных ключей 1253 | * @todo Реализовать более быстрый способ работы 1254 | */ 1255 | int SimpleRedisClient::delete_keys( const char *key) 1256 | { 1257 | if(keys(key)) 1258 | { 1259 | if(getDataSize() < 1 || getBufferSize() < 1) 1260 | { 1261 | return 0; 1262 | } 1263 | 1264 | char **ptr_data = new char*[getDataSize()]; 1265 | 1266 | // Выделяем память для buf_data 1267 | char *buf_data = new char[ getBufferSize() ]; 1268 | memcpy(buf_data, getData(), getBufferSize()); 1269 | 1270 | long int offset = buf_data - getData(); // Опасное дело! 1271 | int num_keys = getDataSize(); 1272 | for(int i =0; i< num_keys; i++) 1273 | { 1274 | ptr_data[i] = getData(i) + offset; 1275 | } 1276 | 1277 | for(int i =0; i< num_keys; i++) 1278 | { 1279 | printf("del[%d]:'%s'\n", i, ptr_data[i]); 1280 | del(ptr_data[i]); 1281 | } 1282 | 1283 | // [SimpleRedisClient.cpp:1171]: (error) Mismatching allocation and deallocation: buf_data 1284 | // Очищаем buf_data 1285 | delete[] buf_data; 1286 | delete[] ptr_data; 1287 | return num_keys; 1288 | } 1289 | 1290 | return -1; 1291 | } 1292 | 1293 | /** 1294 | * Удаляет все найденые ключи, тоесть ищет их командой keys и удаляет каждый найденый ключь. 1295 | * @param key 1296 | * @return Вернёт -1 или количество удалёных ключей 1297 | * @todo Реализовать более быстрый способ работы 1298 | */ 1299 | int SimpleRedisClient::delete_keys_printf(const char *format, ...) 1300 | { 1301 | va_list ap; 1302 | va_start(ap, format); 1303 | bzero(buf, buffer_size); 1304 | int rc = vsnprintf(buf, buffer_size, format, ap); 1305 | va_end(ap); 1306 | if( rc >= buffer_size ) return RC_ERR_BUFFER_OVERFLOW; 1307 | if(rc < 0) return RC_ERR_DATA_FORMAT; 1308 | 1309 | if(redis_send(RC_MULTIBULK, "KEYS '%s'\r\n", buf)) 1310 | { 1311 | if(getDataSize() < 1 || getBufferSize() < 1) 1312 | { 1313 | return 0; 1314 | } 1315 | 1316 | char **ptr_data = new char*[getDataSize()]; 1317 | 1318 | // Выделяем память для buf_data 1319 | char *buf_data = new char[ getBufferSize() ]; 1320 | memcpy(buf_data, getData(), getBufferSize()); 1321 | 1322 | long int offset = buf_data - getData(); // Опасное дело! 1323 | int num_keys = getDataSize(); 1324 | for(int i =0; i< num_keys; i++) 1325 | { 1326 | ptr_data[i] = getData(i) + offset; 1327 | } 1328 | 1329 | 1330 | for(int i =0; i< num_keys; i++) 1331 | { 1332 | printf("del[%d]:'%s'\n", i, ptr_data[i]); 1333 | del(ptr_data[i]); 1334 | } 1335 | 1336 | // Очищаем buf_data 1337 | delete[] buf_data; 1338 | 1339 | delete[] ptr_data; 1340 | return num_keys; 1341 | } 1342 | return -1; 1343 | } 1344 | 1345 | 1346 | int SimpleRedisClient::type( const char *key) 1347 | { 1348 | return redis_send( RC_INLINE, "TYPE '%s'\r\n", key); 1349 | } 1350 | 1351 | int SimpleRedisClient::keys( const char *pattern) 1352 | { 1353 | return redis_send(RC_MULTIBULK, "KEYS '%s'\r\n", pattern); 1354 | } 1355 | 1356 | int SimpleRedisClient::keys_printf(const char *format, ...) 1357 | { 1358 | REDIS_PRINTF_MACRO_CODE(RC_MULTIBULK, "KEYS") 1359 | } 1360 | 1361 | 1362 | int SimpleRedisClient::randomkey() 1363 | { 1364 | return redis_send( RC_BULK, "RANDOMKEY\r\n"); 1365 | } 1366 | 1367 | int SimpleRedisClient::flushall(void) 1368 | { 1369 | return redis_send( RC_INLINE, "FLUSHALL\r\n"); 1370 | } 1371 | 1372 | int SimpleRedisClient::rename( const char *key, const char *new_key_name) 1373 | { 1374 | return redis_send( RC_INLINE, "RENAME '%s' '%s'\r\n", key, new_key_name); 1375 | } 1376 | 1377 | int SimpleRedisClient::rename_printf(const char *format, ...) 1378 | { 1379 | REDIS_PRINTF_MACRO_CODE(RC_INLINE, "RENAME") 1380 | } 1381 | 1382 | int SimpleRedisClient::renamenx( const char *key, const char *new_key_name) 1383 | { 1384 | return redis_send( RC_INT, "RENAMENX '%s' '%s'\r\n", key, new_key_name); 1385 | } 1386 | 1387 | int SimpleRedisClient::renamenx_printf(const char *format, ...) 1388 | { 1389 | REDIS_PRINTF_MACRO_CODE(RC_INT, "RENAMENX") 1390 | } 1391 | 1392 | /** 1393 | * Return the number of keys in the selected database 1394 | */ 1395 | int SimpleRedisClient::dbsize() 1396 | { 1397 | return redis_send( RC_INT, "DBSIZE\r\n"); 1398 | } 1399 | 1400 | int SimpleRedisClient::expire( const char *key, int secs) 1401 | { 1402 | return redis_send( RC_INT, "EXPIRE '%s' %d\r\n", key, secs); 1403 | } 1404 | 1405 | int SimpleRedisClient::expire_printf(const char *format, ...) 1406 | { 1407 | REDIS_PRINTF_MACRO_CODE(RC_INT, "EXPIRE") 1408 | } 1409 | 1410 | 1411 | int SimpleRedisClient::ttl( const char *key) 1412 | { 1413 | return redis_send( RC_INT, "TTL '%s'\r\n", key); 1414 | } 1415 | 1416 | int SimpleRedisClient::ttl_printf(const char *format, ...) 1417 | { 1418 | REDIS_PRINTF_MACRO_CODE(RC_INT, "TTL") 1419 | } 1420 | 1421 | // Списки 1422 | 1423 | int SimpleRedisClient::lpush(const char *key, const char *val) 1424 | { 1425 | return redis_send( RC_INT, "LPUSH '%s' '%s'\r\n", key, val); 1426 | } 1427 | 1428 | int SimpleRedisClient::lpush_printf(const char *format, ...) 1429 | { 1430 | REDIS_PRINTF_MACRO_CODE(RC_INT, "LPUSH") 1431 | } 1432 | 1433 | int SimpleRedisClient::rpush(const char *key, const char *val) 1434 | { 1435 | return redis_send( RC_INT, "RPUSH '%s' '%s'\r\n", key, val); 1436 | } 1437 | 1438 | int SimpleRedisClient::rpush_printf(const char *format, ...) 1439 | { 1440 | REDIS_PRINTF_MACRO_CODE(RC_INT, "RPUSH") 1441 | } 1442 | 1443 | /** 1444 | * LTRIM mylist 1 -1 1445 | */ 1446 | int SimpleRedisClient::ltrim(const char *key, int start_pos, int count_elem) 1447 | { 1448 | return redis_send( RC_INLINE, "LTRIM '%s' %d %d\r\n", key, start_pos, count_elem); 1449 | } 1450 | 1451 | /** 1452 | * LTRIM mylist 1 -1 1453 | */ 1454 | int SimpleRedisClient::ltrim_printf(const char *format, ...) 1455 | { 1456 | REDIS_PRINTF_MACRO_CODE(RC_INLINE, "LTRIM") 1457 | } 1458 | 1459 | /** 1460 | * Выборка с конца очереди (то что попало в очередь раньше других), если все сообщения добавлялись с rpush 1461 | * @param key 1462 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1463 | */ 1464 | int SimpleRedisClient::lpop(const char *key) 1465 | { 1466 | return redis_send( RC_INT, "LPUSH '%s'\r\n", key); 1467 | } 1468 | 1469 | /** 1470 | * Выборка с начала очереди (то что попало в очередь позже других), если все сообщения добавлялись с rpush 1471 | * @param key 1472 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 1473 | */ 1474 | int SimpleRedisClient::lpop_printf(const char *format, ...) 1475 | { 1476 | REDIS_PRINTF_MACRO_CODE(RC_BULK, "LPOP") 1477 | } 1478 | 1479 | int SimpleRedisClient::rpop(const char *key) 1480 | { 1481 | return redis_send( RC_INT, "RPUSH '%s'\r\n", key); 1482 | } 1483 | 1484 | int SimpleRedisClient::rpop_printf(const char *format, ...) 1485 | { 1486 | REDIS_PRINTF_MACRO_CODE(RC_BULK, "RPOP") 1487 | } 1488 | 1489 | int SimpleRedisClient::llen(const char *key) 1490 | { 1491 | return redis_send( RC_INT, "LLEN '%s'\r\n", key); 1492 | } 1493 | 1494 | int SimpleRedisClient::llen_printf(const char *format, ...) 1495 | { 1496 | REDIS_PRINTF_MACRO_CODE(RC_INT, "LLEN") 1497 | } 1498 | 1499 | 1500 | int SimpleRedisClient::lrem(const char *key, int n,const char* val) 1501 | { 1502 | return redis_send( RC_INT, "LLEN '%s' %d '%s' \r\n", key, n, val); 1503 | } 1504 | 1505 | int SimpleRedisClient::lrem_printf(const char *format, ...) 1506 | { 1507 | REDIS_PRINTF_MACRO_CODE(RC_INT, "LREM") 1508 | } 1509 | 1510 | 1511 | int SimpleRedisClient::lrange(const char *key, int start, int stop) 1512 | { 1513 | return redis_send( RC_INT, "LRANGE '%s' %d %d\r\n", key, start, stop); 1514 | } 1515 | 1516 | int SimpleRedisClient::lrange_printf(const char *format, ...) 1517 | { 1518 | REDIS_PRINTF_MACRO_CODE(RC_MULTIBULK, "LRANGE") 1519 | } 1520 | 1521 | 1522 | int SimpleRedisClient::incr(const char *key) 1523 | { 1524 | return redis_send( RC_INT, "INCR '%s'\r\n", key); 1525 | } 1526 | 1527 | int SimpleRedisClient::incr_printf(const char *format, ...) 1528 | { 1529 | REDIS_PRINTF_MACRO_CODE(RC_INT, "INCR") 1530 | } 1531 | 1532 | int SimpleRedisClient::decr(const char *key) 1533 | { 1534 | return redis_send( RC_INT, "DECR '%s'\r\n", key); 1535 | } 1536 | 1537 | int SimpleRedisClient::decr_printf(const char *format, ...) 1538 | { 1539 | REDIS_PRINTF_MACRO_CODE(RC_INT, "DECR") 1540 | } 1541 | 1542 | int SimpleRedisClient::operator +=( const char *key) 1543 | { 1544 | return redis_send( RC_INT, "INCR '%s'\r\n", key); 1545 | } 1546 | 1547 | int SimpleRedisClient::operator -=( const char *key) 1548 | { 1549 | return redis_send( RC_INT, "DECR '%s'\r\n", key); 1550 | } 1551 | 1552 | /** 1553 | * 1554 | * @param TimeOut 1555 | */ 1556 | void SimpleRedisClient::setTimeout( int TimeOut) 1557 | { 1558 | timeout = TimeOut; 1559 | } 1560 | 1561 | /** 1562 | * Закрывает соединение 1563 | */ 1564 | void SimpleRedisClient::redis_close() 1565 | { 1566 | if(debug > RC_LOG_DEBUG) printf("close ok %d\n", fd); 1567 | if(fd != 0 ) 1568 | { 1569 | close(fd); 1570 | } 1571 | } 1572 | 1573 | 1574 | SimpleRedisClient::operator bool () const 1575 | { 1576 | return fd != 0; 1577 | } 1578 | 1579 | int SimpleRedisClient::operator == (bool d) 1580 | { 1581 | return (fd != 0) == d; 1582 | } 1583 | 1584 | 1585 | char* SimpleRedisClient::getData() const 1586 | { 1587 | return data; 1588 | } 1589 | 1590 | int SimpleRedisClient::getDataSize() const 1591 | { 1592 | return data_size; 1593 | } 1594 | -------------------------------------------------------------------------------- /for-redis-2.8/SimpleRedisClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * File: SimpleRedisClient.h 3 | * Author: victor 4 | * 5 | * Created on 10 Август 2013 г., 22:26 6 | */ 7 | 8 | #ifndef SIMPLEREDISCLIENT_H 9 | #define SIMPLEREDISCLIENT_H 10 | 11 | 12 | #define RC_NULL 0 13 | #define RC_ERR -1 14 | 15 | #define RC_ERR_CONECTION_CLOSE -2 16 | #define RC_ERR_SEND -101 17 | #define RC_ERR_TIMEOUT -102 18 | #define CR_ERR_RECV -103 19 | 20 | #define RC_ERR_PROTOCOL -104 21 | #define RC_ERR_BUFFER_OVERFLOW -105 22 | #define RC_ERR_DATA_FORMAT -106 23 | 24 | #define RC_ERR_DATA_BUFFER_OVERFLOW -107 25 | 26 | 27 | #define RC_LOG_NONE 0 28 | #define RC_LOG_ERROR 1 29 | #define RC_LOG_WARN 2 30 | #define RC_LOG_LOG 3 31 | #define RC_LOG_DEBUG 4 32 | 33 | /** 34 | * Тип ожидаемых от редиса данных 35 | */ 36 | #define RC_ERROR '-' 37 | 38 | /** 39 | * Тип ожидаемых от редиса данных 40 | * Строка в ответе 41 | * @see http://redis.io/topics/protocol 42 | */ 43 | #define RC_INLINE '+' 44 | 45 | /** 46 | * Тип ожидаемых от редиса данных 47 | * Определяет длину аргумента ответа 48 | * -1 нет ответа 49 | * @see http://redis.io/topics/protocol 50 | */ 51 | #define RC_BULK '$' 52 | 53 | /** 54 | * Тип ожидаемых от редиса данных 55 | * Определяет количество аргументов ответа 56 | * -1 нет ответа 57 | * @see http://redis.io/topics/protocol 58 | */ 59 | #define RC_MULTIBULK '*' 60 | 61 | /** 62 | * Тип ожидаемых от редиса данных 63 | */ 64 | #define RC_INT ':' 65 | 66 | /** 67 | * Тип ожидаемых от редиса данных 68 | */ 69 | #define RC_ANY '?' 70 | 71 | /** 72 | * Тип ожидаемых от редиса данных 73 | */ 74 | #define RC_NONE ' ' 75 | 76 | int read_int(const char* buffer, char delimiter, int* delta); 77 | int read_int(const char* buffer, char delimiter); 78 | int read_int(const char* buffer, int* delta); 79 | 80 | long read_long(const char* buffer, char delimiter, int* delta); 81 | long read_long(const char* buffer, char delimiter); 82 | long read_long(const char* buffer, int* delta); 83 | 84 | class SimpleRedisClient 85 | { 86 | int fd = 0; 87 | int yes = 1; 88 | int timeout = 1000; 89 | 90 | char* buffer = 0; 91 | char* buf = 0; 92 | int buffer_size = 0; 93 | 94 | /** 95 | * Максимально допустимый размер буфера 96 | */ 97 | int max_buffer_size = 1000000; 98 | 99 | 100 | int port = 6379; 101 | char* host = 0; 102 | 103 | int version_major = -1; 104 | int version_minor = -1; 105 | int version_patch = -1; 106 | 107 | /** 108 | * Хранит количество пришедших данных в ответе. 109 | * Для списка это колво элементов для остальных типов это колво байт. 110 | */ 111 | unsigned int data_size = 0; 112 | 113 | char* data = 0; 114 | int answer_int = 0; 115 | 116 | int multibulk_arg = 0; 117 | char** answer_multibulk = 0; 118 | 119 | int debug = 0; 120 | 121 | int last_error = 0; 122 | 123 | private: 124 | 125 | /** 126 | * Запрещаем копирование для объектов донного класса 127 | * Если открыто соединение с редисом, а потом выполнена копия объекта 128 | * то при удалении любого из объектов в деструкторе соединение закроется. 129 | * ,а при удалении второго вообще ни чего хорошего ждать не надо. 130 | * 131 | * Возможно в следующих версиях библиотеки будет реализован адекватный конструктор копирования. 132 | */ 133 | SimpleRedisClient(const SimpleRedisClient& ) = delete; 134 | 135 | /** 136 | * Запрещаем копирование для объектов донного класса 137 | * Возможно в следующих версиях библиотеки будет реализован адекватный конструктор копирования. 138 | */ 139 | void operator=( const SimpleRedisClient& ) = delete; 140 | 141 | public: 142 | 143 | void LogLevel(int); 144 | int LogLevel(void); 145 | 146 | SimpleRedisClient(); 147 | 148 | void setPort(int Port); 149 | 150 | void setHost(const char* Host); 151 | 152 | virtual ~SimpleRedisClient(); 153 | 154 | int redis_conect(); 155 | int redis_conect(const char* Host, int Port); 156 | int redis_conect(const char* Host,int Port, int TimeOut); 157 | 158 | /* 159 | vector3 operator-=(float v); 160 | bool operator==(vector3 v); 161 | */ 162 | 163 | char** getMultiBulkData(); 164 | int getMultiBulkDataAmount(); 165 | 166 | /** 167 | * Ни ключь ни значение не должны содержать "\r\n" 168 | * @param key 169 | * @param val 170 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 171 | */ 172 | int set(const char *key, const char *val); 173 | 174 | /** 175 | * Операция set только с форматированием строки параметров. 176 | * Ключ от значения отделяется пробелом. 177 | * @param format 178 | * @param ... ключь пробел значение 179 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 180 | */ 181 | int set_printf(const char *format, ...); 182 | 183 | /** 184 | * 185 | * @param key Ключ 186 | * @param format 187 | * @param ... значение 188 | * @return 189 | int set_printf(const char *key, const char *format, ...); 190 | */ 191 | 192 | /** 193 | * Выполняет установку значения в редис 194 | * Ключ от значения отделяется пробелом. 195 | * @code rc = "MyKey MyValue"; 196 | * 197 | * 198 | * @param key_val 199 | * @return 200 | */ 201 | SimpleRedisClient& operator=(const char *key_val); 202 | 203 | /** 204 | * Вернёт значение ключа или 0 в случаии отсутсвия ключа или ошибки 205 | * Пример: 206 | * 207 | * char* val = rc["key"]; 208 | * if(val != 0) 209 | * { 210 | * printf("VAL:%s\n", val); 211 | * } 212 | * 213 | * Выдаётся указатьель на внутриний буфер чтения/записи ссылка потеряет актуальность при вызове любой функции на получение или запись данных. 214 | * Или по указаному адресу будут уже другие данные либо мусор. 215 | */ 216 | char* operator[] (const char *key); 217 | 218 | 219 | /** 220 | * Равносильно методу getData() 221 | * @return 222 | */ 223 | operator char* () const; 224 | 225 | /** 226 | * Равносильно методу getData() с преобразованием в int 227 | * @return 228 | */ 229 | operator int () const; 230 | 231 | /** 232 | * Равносильно методу getData() с преобразованием в long 233 | * @return 234 | */ 235 | operator long () const; 236 | 237 | /** 238 | * Инкриментирует значение ключа key, эквивалентно incr 239 | * @param key ключь в редисе 240 | * @return 241 | */ 242 | int operator +=( const char *key); 243 | 244 | /** 245 | * Декриментирует значение ключа key, эквивалентно decr 246 | * @param key ключь в редисе 247 | * @return 248 | */ 249 | int operator -=( const char *key); 250 | 251 | /** 252 | * Вернёт true если соединение установлено 253 | */ 254 | operator bool () const; 255 | 256 | /** 257 | * rc == true истино если соединение установлено 258 | * rc == false истино если соединение не установлено 259 | */ 260 | int operator == (bool); 261 | 262 | int incr(const char *key); 263 | int incr_printf(const char *format, ...); 264 | 265 | int decr(const char *key); 266 | int decr_printf(const char *format, ...); 267 | 268 | int setex(const char *key, const char *val, int seconds); 269 | int setex_printf(int seconds, const char *key, const char *format, ...); 270 | 271 | /** 272 | * Формат должен иметь вид: key seconds data 273 | * Где 274 | * key строковый ключ 275 | * seconds %d число секунд 276 | * data строковые данные 277 | * 278 | * @param format 279 | * @param ... 280 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 281 | */ 282 | int setex_printf(const char *format, ...); 283 | 284 | int get(const char *key); 285 | int get_printf( const char *format, ...); 286 | 287 | 288 | /** 289 | * Set the string value of a key and return its old value 290 | * @param key 291 | * @param set_val 292 | * @param get_val 293 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 294 | */ 295 | int getset(const char *key, const char *set_val); 296 | int getset_printf(const char *format, ...); 297 | 298 | /** 299 | * Ping the server 300 | */ 301 | int ping(); 302 | 303 | int echo(const char *message); 304 | 305 | int quit(); 306 | 307 | int auth(const char *password); 308 | 309 | int setnx(const char *key, const char *val); 310 | int setnx_printf(const char *format, ...); 311 | 312 | /** 313 | * http://redis.io/commands 314 | * 315 | * 316 | * static int cr_incr(REDIS rhnd, int incr, int decr, const char *key, int *new_val) 317 | * credis_incr 318 | * credis_decr 319 | * credis_incrby 320 | * credis_decrby 321 | * 322 | * 323 | * cr_multikeybulkcommand 324 | * cr_multikeystorecommand 325 | * credis_mget 326 | * 327 | * Set multiple keys to multiple values 328 | * MSET key value [key value ...] 329 | */ 330 | 331 | int append(const char *key, const char *val); 332 | int append_printf(const char *format, ...); 333 | 334 | int substr( const char *key, int start, int end); 335 | 336 | int exists( const char *key); 337 | int exists_printf(const char *format, ...); 338 | 339 | int del( const char *key); 340 | int del_printf(const char *format, ...); 341 | 342 | int delete_keys( const char *key); 343 | int delete_keys_printf(const char *format, ...); 344 | 345 | int type( const char *key); 346 | 347 | int keys(const char *pattern); 348 | int keys_printf(const char *format, ...); 349 | 350 | int randomkey(); 351 | 352 | int rename( const char *key, const char *new_key_name); 353 | int rename_printf(const char *format, ...); 354 | 355 | int renamenx( const char *key, const char *new_key_name); 356 | int renamenx_printf(const char *format, ...); 357 | 358 | /** 359 | * Return the number of keys in the selected database 360 | */ 361 | int dbsize(); 362 | 363 | int expire( const char *key, int secs); 364 | int expire_printf(const char *format, ...); 365 | 366 | 367 | int flushall(void); 368 | 369 | int sadd(const char *key, const char *member); 370 | int sadd_printf(const char *format, ...); 371 | 372 | int srem(const char *key, const char *member); 373 | int srem_printf(const char *format, ...); 374 | 375 | int smembers(const char *key); 376 | int smembers_printf(const char *format, ...); 377 | 378 | int scard(const char *key); 379 | int scard_printf(const char *format, ...); 380 | 381 | int lpush(const char *key, const char *member); 382 | int lpush_printf(const char *format, ...); 383 | 384 | int rpush(const char *key, const char *member); 385 | int rpush_printf(const char *format, ...); 386 | 387 | int ltrim(const char *key, int start_pos, int count_elem); 388 | int ltrim_printf(const char *format, ...); 389 | 390 | int lpop(const char *key); 391 | int lpop_printf(const char *format, ...); 392 | 393 | int rpop(const char *key); 394 | int rpop_printf(const char *format, ...); 395 | 396 | int llen(const char *key); 397 | int llen_printf(const char *format, ...); 398 | 399 | int lrem(const char *key, int n,const char* val); 400 | int lrem_printf(const char *format, ...); 401 | 402 | int lrange(const char *key, int start, int stop); 403 | int lrange_printf(const char *format, ...); 404 | 405 | 406 | /** 407 | * Returns the remaining time to live of a key that has a timeout. 408 | * @param key 409 | * @return 410 | */ 411 | int ttl( const char *key); 412 | int ttl_printf(const char *format, ...); 413 | 414 | 415 | int getRedisVersion(); 416 | 417 | /** 418 | * 419 | * @param TimeOut 420 | */ 421 | void setTimeout( int TimeOut); 422 | 423 | /** 424 | * Закрывает соединение 425 | */ 426 | void redis_close(); 427 | 428 | /** 429 | * Выдаётся указатьель на внутриний буфер чтения/записи ссылка потеряет актуальность при вызове любой функции на получение или запись данных. 430 | * Или по указаному адресу будут уже другие данные либо мусор. 431 | */ 432 | char* getData() const; 433 | char* getData(int i) const; 434 | 435 | /** 436 | * Возвращает количество пришедших данных в ответе. 437 | * Для списка это колво элементов для остальных типов это колво байт. 438 | */ 439 | int getDataSize() const; 440 | 441 | void setBufferSize(int size); 442 | int getBufferSize(); 443 | 444 | void setMaxBufferSize(int size); 445 | int getMaxBufferSize(); 446 | 447 | /** 448 | * Выбор бызы данных 449 | * @param index 450 | * @see http://redis.io/commands/select 451 | */ 452 | int selectDB(int index); 453 | 454 | int getError(); 455 | 456 | int redis_raw_send(char recvtype, const char *buffer); 457 | protected: 458 | 459 | char* lastAuthPw = NULL; 460 | int lastSelectDBIndex = 0; 461 | 462 | int reconect( ); 463 | 464 | 465 | int read_select(int fd, int timeout ) const; 466 | 467 | int wright_select(int fd, int timeout ) const; 468 | 469 | /** 470 | * Отправляет запрос редису 471 | * @param recvtype тип ожидаемого результата 472 | * @param format Строка запроса 473 | * @param ... 474 | * @return Если меньше нуля то код ошибки, а если больше нуля то количество принятых байт 475 | */ 476 | int redis_send(char recvtype, const char *format, ...); 477 | 478 | /** 479 | * Отправляет данные 480 | * @param buf 481 | * @return 482 | */ 483 | int send_data( const char *buf ) const; 484 | 485 | }; 486 | 487 | 488 | 489 | #endif /* SIMPLEREDISCLIENT_H */ 490 | 491 | -------------------------------------------------------------------------------- /for-redis-2.8/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "SimpleRedisClient.h" 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | SimpleRedisClient rc; 8 | 9 | rc.setHost("127.0.0.1"); 10 | rc.auth("home"); 11 | rc.LogLevel(0); 12 | 13 | if(!rc) 14 | { 15 | printf("Соединение с redis не установлено\n"); 16 | return -1; 17 | } 18 | 19 | rc = "MYKEY my-value-tester"; 20 | if(rc["MYKEY"]) 21 | { 22 | printf("MYKEY == [%d][%s]\n", (int)rc, (char*)rc); 23 | } 24 | 25 | printf("-------------------\n"); 26 | rc.sadd_printf("%s %d", "MY_SET", 123); 27 | rc.sadd_printf("%s %d", "MY_SET", 14); 28 | 29 | rc.smembers("MY_SET"); 30 | 31 | if(rc.getMultiBulkDataAmount()) 32 | { 33 | for(int i =0; i< rc.getMultiBulkDataAmount(); i++ ) 34 | { 35 | printf("Answer[%d]->%s\n", i, rc.getData(i)); 36 | } 37 | } 38 | 39 | rc = "MYKEY1 my-value-tester"; 40 | rc = "MYKEY2 my-value-tester"; 41 | 42 | rc.delete_keys("MY*"); 43 | 44 | rc.redis_close(); 45 | } --------------------------------------------------------------------------------