├── 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 |
12 | - Добавлена поддержка redis версии 2.8
13 | - Автоматически переподключается при потере соединения
14 | - Добавлены некоторые функции от redis такие как select, dbsize и другие
15 | - Поправлены баги работы с сетью
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 |
--------------------------------------------------------------------------------
/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 |
13 | - Автоматически переподключается при потере соединения
14 | - Добавлены некоторые функции от redis такие как select, dbsize и другие
15 | - Поправлены баги работы с сетью
16 |
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 | }
--------------------------------------------------------------------------------