Hi everyone,
I wrote a c memcached client. The reason I wrote it is
because spymemcached has some problems, say "connection reset by peer". And
the problems has driven crazy, so a idea came up , what about write a
client.
I hope it can help you. It has two files,
MemcachedControl.c and MemcachedControl.h. It is easy to use my client,
include the head file into your c file. When you want to set/add/.......
key, you have to call the initialize the data structure. I wrote an example
in the MemcachedControl.c .
If you have any problem, please mail me , just mail me ,
thank you in advance.
--
Best Regards
Tony Cui
#include "memcachedControl.h"
/*
* @author: Cui Li Ming a student of ustc.
*/
static int lengthPick( const char * data );
static int checkKey ( const char * key );
static msgT msgFactory ( int length,iovT iov );
//int main() {
// memcacheT * test = initMemcached( "192.168.1.21:11211" );
//
// test->set( test,"10000","hello world" );
//// fprintf( stderr,"the value is %s \n",test->get(test,"100") );
//
//// int i = 0;
//// char **eye = test->gets( test,"100 101" );
//// while( eye[i] != 0 ) {
//// if ( eye[ i ] != 0 ) {
//// fprintf( stderr," the reason is %s ",eye[ i ] );
//// }
//// i++;
//// }
//// fprintf( stderr,"%d\n",test->delete( test,"101" ) );
//// fprintf( stderr,"%d\n",test->add( test,"107","200" ) );
//// fprintf( stderr,"%d\n",test->decr( test,"107",20 ));
//
//// return 0;
//}
/*
*initialize the structure memcacheT. This is the first function, when you want to use it.
*
*address ip:port
*/
memcacheT * initMemcached ( const char * address ) {
memcacheT * connection = 0;
connection = ( memcacheT * ) calloc (1,sizeof( memcacheT ) );
if ( !connection ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
#if DEBUG
#endif
connection->ip = calloc( 20,sizeof( char ) );
if( !connection->ip ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
char *ipOperator = connection->ip;
connection->port =( char * )malloc ( 10*sizeof( char ) );
if ( !connection->port ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
char * portOperator = connection->port;
while ( *address != ':' ) {
*(ipOperator++) = *(address++);
#if DEBUG
fprintf( stderr," the ipOperator is %c \n",*address );
fprintf( stderr," the ............... is %c \n",*(ipOperator-8) );
#endif
}
*( ++ipOperator ) = '\0';
++address;
while( *address ) {
*( portOperator++ ) = *( address++ );
}
int socketC = socket( AF_INET,SOCK_STREAM,0 );
if (!socketC) {
fprintf( stderr," can not create the socket\n " );
exit( 1 );
}
connection->socket = socketC;
connection->set = & setCommand;
connection->get = & getCommand;
connection->gets = & getsmem;
connection->delete = & deleteCommand;
connection->add = & addCommand;
connection->incr = & incrCommand;
connection->decr = & decrCommand;
connection->server.sin_family = AF_INET;
int serverPort = 0;
// sprintf( connection->port,"%d",serverPort );
connection->server.sin_port = htons( atoi(connection->port) );
if ( inet_aton( connection->ip,&connection->server.sin_addr ) == -1) {
fprintf( stderr," ip error\n " );
exit( 1 );
}
if ( connect ( connection->socket,( struct sockaddr * )&connection->server,sizeof( connection->server ) ) == -1 ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
return connection;
}
/*
* set action , you can use connection->set( connection,key,value,falg );
*
* connection: the structure you use this client.
* key: when you want to store a value, you have a key ~~~
* value: the one stored in memcached.
*
*return 1 succeed -1 failed.
*/
int setCommand ( memcacheT * connection,const char * key,const char * value ) {
return setCommandProcess ( connection,key,value,0 );
}
/*
* to process the add and set command.
*
* connection: our data structure.
* key: you want to store.
* value: you want to store.
* flag: 1 is add command , 0 is set command.
*
* return -1 failed, 1 succeed.
*/
int setCommandProcess ( memcacheT * connection,const char * key,const char * value,int flag ) {
char * sendKey = ( char * ) calloc( strlen( key )+30,sizeof( char ) );
if ( !sendKey ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
char * sendKeyOperator = sendKey;
char * keyLength = ( char * )calloc( strlen( key ),sizeof( 10 ) );
if ( !keyLength ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
char * keyLengthOperator = keyLength;
if ( flag == 1 ) {
strcat( sendKeyOperator,"add " );
}else if ( flag == 0 ) {
strcat( sendKeyOperator,"set " );
}
strcat ( sendKeyOperator,key );
strcat( sendKeyOperator," 0 0 " );
sprintf( keyLengthOperator,"%d",strlen( value ) );
strcat( sendKeyOperator,keyLengthOperator );
strcat( sendKeyOperator,"\r\n" );
*( sendKeyOperator + strlen( sendKeyOperator ) ) = ' \0';
char * sendData = ( char * ) calloc ( strlen( value ) + 5,sizeof( char ) );
if ( !sendData ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
char * sendDataOperator = sendData;
strcpy( sendDataOperator,value );
strcat ( sendDataOperator,"\r\n" );
*( sendDataOperator + strlen( sendDataOperator ) ) = '\0';
msgT msgR;
iovT iovR;
msgR.msg_name = 0;
msgR.msg_namelen = 0;
msgR.msg_control = 0;
msgR.msg_controllen = 0;
msgR.msg_flags = 0;
msgR.msg_iov = &iovR;
msgR.msg_iovlen = 1;
iovR.iov_base = ( char * ) calloc( 20,sizeof( char ) );
if ( !iovR.iov_base ) {
fprintf( stderr," calloc error \n " );
exit ( 1 );
}
iovR.iov_len = 20;
char * receiveOperator = iovR.iov_base;
#if TONY_D
if ( write( connection->socket,sendKeyOperator,strlen( sendKeyOperator ) ) == -1 ) {
fprintf( stderr," send error \n " );
}
#endif
msgT sendmsgHere ;
iovT ioc[2];
ioc[0].iov_base = sendKeyOperator;
ioc[0].iov_len = strlen( sendKeyOperator );
ioc[1].iov_base = sendDataOperator;
ioc[1].iov_len = strlen( sendDataOperator );
sendmsgHere.msg_iov = ioc;
sendmsgHere.msg_iovlen = 2;
sendmsgHere.msg_control = 0;
sendmsgHere.msg_controllen = 0;
sendmsgHere.msg_flags = 0;
sendmsgHere.msg_name = 0;
sendmsgHere.msg_namelen = 0;
if ( sendmsg( connection->socket,&sendmsgHere,0 ) == -1 ) {
fprintf( stderr," send error \n " );
}
#if TONY_D
if ( write( connection->socket,sendDataOperator,strlen( sendDataOperator ) ) == -1 ) {
fprintf( stderr," send error \n " );
}
#endif
#if TONY_D
while( read( connection->socket,receiveOperator,12 ) > 0 ) {
fprintf( stderr," %s \n ",receiveOperator );
break;
}
#endif
recvmsg( connection->socket,&msgR,0);
#if DEBUG
fprintf( stderr," %s ",receiveOperator );
#endif
int ret = 0;
if ( *receiveOperator == 'N'&&*( receiveOperator + 1 ) == 'O'&&*(receiveOperator + 2) == 'T') {
ret = -1;
}else if ( *receiveOperator == 'S'&&*( receiveOperator +1 ) == 'T'&&*( receiveOperator + 2) == 'O' ) {
ret = 1;
}
free( sendKey );
free( sendData );
free( keyLength );
free( msgR.msg_iov->iov_base );
return ret;
}
/*
*to process get command.
*
* connection: our structure.
* key: you want to query with.
*
* return the value.
*/
char * getCommand ( memcacheT * connection,char * key ) {
char * received = ( char * ) calloc ( 100,sizeof( char ) );
if ( !received ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
char * receivedOperator = received;
char * receivedAnaylisis = received;
char * keyHere = ( char * ) calloc ( 100,sizeof( char ) );
if ( !keyHere ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
char * keyOperator = keyHere;
strcat( keyOperator,"get " );
strcat( keyOperator,key );
strcat( keyOperator," \r\n" );
if ( write( connection->socket,keyOperator,strlen( keyOperator ) ) == -1 ) {
fprintf( stderr," write error \n " );
}
char r;
while( r != '\n' ) {
read( connection->socket,&r,1 );
*( receivedOperator++ ) = r;
}
char * lengthValue = calloc(20,sizeof( char ) );
if ( !lengthValue ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
char * lengthOperator = lengthValue;
char * temp = 0;
int counter = 0;
while( *(receivedAnaylisis++) != '\r' );
temp = receivedAnaylisis;
while( *( --receivedAnaylisis ) != ' ' ) { ++counter; };
strncpy( lengthOperator,receivedAnaylisis,counter );
#if DEBUG
fprintf( stderr," the length is %d \n ",atoi(lengthOperator) );
#endif
int valueLength = atoi(lengthOperator);
char * value = calloc( valueLength + 8,sizeof( char ) );
if ( !value ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
read( connection->socket,value,valueLength + 8 );
#if DEBUG
fprintf( stderr," value is %s \n ", value);
#endif
free( received );
free( keyHere );
free( lengthValue );
return value;
}
/*
* to process the gets. It means get muti-keys from memcached.
*
* connection: our structure.
* keys: like "100 101",separated by space
*
* return char **ret , you can get one , with ret[ 0 ].
*/
char ** getsmem ( memcacheT * connection,const char * keys ) {
if ( !checkKey( keys ) ) {
return 0;
}
char * sendCommand = calloc( strlen( keys ) + 10,sizeof( char ) );
if ( !sendCommand ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
char * sendCommandOperator = sendCommand;
strcat( sendCommandOperator,"get " );
strcat( sendCommandOperator,keys );
strcat( sendCommandOperator," \r\n" );
if ( write( connection->socket,sendCommandOperator,strlen( sendCommandOperator ) ) == -1 ) {
fprintf( stderr," write error \n " );
}
char * keysCount = keys;
int counterKeys = 1;
while( *(keysCount++) ) {
if ( *keysCount ==' ' ) {counterKeys++ ;}
}
char ** ret = calloc( counterKeys,sizeof( char * ) );
if ( !ret ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
char * receivedData = calloc( 100,sizeof( char ) );
if ( !receivedData ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
iovT iov;
msgT msg;
// struct msghdr msg ;
// struct iovec iov;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_iov->iov_base = calloc( 1024*1024,sizeof( char ) );
if ( !msg.msg_iov->iov_base ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
msg.msg_iov->iov_len = 1024*1024;
msg.msg_control = 0;
msg.msg_controllen = 0;
// msg.msg_iov->iov_base = calloc( 1024*1024,sizeof( char ) );
// if ( !msg.msg_iov->iov_base ) {
// fprintf( stderr," calloc error \n " );
// exit( 1 );
// }
char * msgOperator = msg.msg_iov->iov_base;
recvmsg( connection->socket,&msg,0 );
int i = 0;
for ( i = 0;i < counterKeys;i++ ) {
#if WILLBE
char * receivedOperator = receivedData;
char p ;
while( p != '\n' ) {
*( receivedOperator++ ) = p;
}
int m = lengthPick( receivedData );
ret[i] = calloc( m + 4,sizeof( char ) );
if ( !ret[i] ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
read( connection->socket,ret[i],m+4 );
#endif
#if DEBUG
fprintf( stderr," the value is %s ",msg.msg_iov->iov_base );
#endif
char * research = msgOperator;
if ( research == 0 ) break;
int lengthValue = lengthPick(msgOperator);
if ( lengthValue == -1 ) {
ret [ i ] = "NULL";
continue;
}
while( *(research++) != '\n' );
ret[i] = calloc( lengthValue + 2,sizeof( char ) );
if ( !ret[i] ) {
fprintf( stderr,"received error \n" );
exit( 1 );
}
strncpy( ret[i],research,lengthValue + 2 );
#if DEBUG
fprintf( stderr," the reti is %s\n",ret[i] );
#endif
if ( research )
research += (lengthValue + 2);
msgOperator = research;
}
free( msg.msg_iov->iov_base );
free( receivedData );
free( sendCommand );
return ret;
}
/*
* to process delete command.
* connection: our structure.
* keys: you want to query with.
*
* return -1 failed, 1 succeed.
*/
int deleteCommand ( memcacheT * connection,const char * key) {
if ( !checkKey( key ) ) {
return 0;
}
char * sendCommand = calloc( strlen(key) + 10,sizeof( char ) );
if ( !sendCommand ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
char * sendOperator = sendCommand;
strcat( sendOperator,"delete " );
strcat( sendOperator,key );
strcat( sendOperator,"\r\n" );
if ( write( connection->socket,sendOperator,strlen(sendOperator) ) == -1 ) {
fprintf( stderr," write error \n " );
exit( 1 );
}
iovT iov;
msgT msg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_iov->iov_len = 20;
msg.msg_iov->iov_base = calloc( 20,sizeof( char ) );
if ( !msg.msg_iov->iov_base ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
char * receivedOperator = msg.msg_iov->iov_base;
recvmsg( connection->socket,&msg,0 );
int ret = 0;
if ( *receivedOperator == 'N' ) {
ret = -1;
}else if ( *receivedOperator == 'D' ) {
ret = 1;//delete succeed
}
free( sendCommand );
free( msg.msg_iov->iov_base );
return ret;
}
/*
*to process add command
*connection: our structure.
*key: to find the value.
*value: you want to add to the original value.
*
*return the value after operation,or return -1 this is no value according to key stored .
*/
int addCommand( memcacheT * connection,const char * key,const char * value ) {
#if WILLBE
if ( !checkKey( key ) ) {
return 0;
}
char * sendCommand = calloc( strlen( key ) + 10,sizeof( char ) );
if ( !sendCommand ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
char * sendOperator = sendCommand;
strcat ( sendOperator,"add " );
strcat ( sendOperator,key );
strcat ( sendOperator,"\r\n" );
if ( write( connection->socket,sendOperator,strlen( sendOperator ) ) == -1 ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
iovT iov;
msgT msg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_iov->iov_base = calloc( 20,sizeof( char ) );
if ( !msg.msg_iov->iov_base ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
int ret = 0;
char * receivedOperator = msg.msg_iov->iov_base;
recvmsg( connection->socket,&msg,0 );
if ( *receivedOperator == 'S' ){
ret = 1;
}else if ( *receivedOperator == 'N' ) {
ret = -1;
}
free( sendCommand );
free( msg.msg_iov->iov_base );
return ret;
#endif
return setCommandProcess ( connection,key,value,1 );
}
int incrCommand ( memcacheT *connection,const char * key,int value,int flag ) {
char * sendCommand = calloc( strlen( key ) + 40,sizeof( char ) );
if ( !sendCommand ) {
fprintf( stderr,"calloc error \n" );
exit( 1 );
}
char * sendOperator = sendCommand;
if ( flag == 0 ) {
strcat ( sendOperator,"incr " );
}else if (flag == 1) {
strcat ( sendOperator,"decr " );
}
strcat ( sendOperator,key );
char * lenghtRoom = calloc( 10,sizeof( char ) );
if( !lenghtRoom ) {
fprintf( stderr,"calloc error \n" );
exit( 1 );
}
sprintf( lenghtRoom,"%d",value );
strcat ( sendOperator," " );
strcat ( sendOperator,lenghtRoom );
strcat ( sendOperator,"\r\n" );
if ( write( connection->socket,sendOperator,strlen( sendOperator ) ) == -1 ) {
fprintf( stderr," write error \n " );
exit( 1 );
}
msgT msg;
iovT iov;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
iov.iov_base = calloc( 200,sizeof( char ) );
if ( !iov.iov_base ) {
fprintf( stderr,"calloc error \n" );
exit( 1 );
}
char *receiveOperator = iov.iov_base;
iov.iov_len = 200;
recvmsg( connection->socket,&msg,0 );
int ret = 0;
if ( *receiveOperator == 'C' ) {
ret = -1;
}else {
ret = atoi( receiveOperator );
}
free( iov.iov_base );
free( lenghtRoom );
free( sendCommand );
return ret;
}
int decrCommand ( memcacheT *connection,const char * key,int value ) {
#if WIILBE
char * sendCommand = calloc( strlen( key ) + 30,sizeof( char ) );
if ( !sendCommand ) {
fprintf( stderr,"calloc error \n" );
exit( 1 );
}
char * sendOperator = sendCommand ;
free( sendCommand );
#endif
return connection->incr( connection,key,value,1 );
}
static int lengthPick( const char * data ) {
char * dataOperator = data;
char * dataAnalysis = data;
if ( *dataOperator == 'E' && *(dataOperator + 1) =='N'&& *(dataOperator + 2) == 'D' ) {
return -1;
}
if ( *dataOperator == 'N' && *(dataOperator + 1) =='O'&& *(dataOperator + 2) == 'T' ) {
return -1;
}
while ( *( dataOperator++ ) != '\r' );
dataAnalysis = dataOperator;
int counter = 0;
while( *( --dataOperator ) != ' ' ){ counter++; }
char * lengthRoom = calloc( 20,sizeof( char ) );
if ( !lengthRoom ) {
fprintf( stderr,"calloc error \n" );
exit( 1 );
}
strncpy( lengthRoom,dataOperator,counter );
int ret = atoi( lengthRoom );
free( lengthRoom );
return ret;
}
static int checkKey ( const char * key ) {
char * operator = key;
if ( strlen( operator ) == 1 && *operator == ' ' ) {
return 0;
}else if ( strlen( operator ) == 0 ) {
return 0;
}else {
return 1;
}
}
/*
* @unused.
* I want to build a factory to produce the msg ( msghdr ), and I failed.
* If you could build one, maile me.
*/
static msgT msgFactory ( int length,iovT iov ) {
msgT msg;
msg.msg_name = 0;
msg.msg_namelen = 0;
msg.msg_control = 0;
msg.msg_controllen = 0;
msg.msg_flags = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_iov->iov_base = calloc( length,sizeof( char ) );
iov.iov_len = length;
if ( !msg.msg_iov->iov_base ) {
fprintf( stderr," calloc error \n " );
exit( 1 );
}
return msg;
}
#ifndef MEMECACHED_H
#define MEMECACHED_H 1
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <netdb.h>
#define TONY_D 0
#define DEBUG 0
#define WLLBE 0
typedef struct memcacheC memcacheT;
typedef struct msghdr msgT;
typedef struct iovec iovT;
struct memcacheC {
int ( * set )( memcacheT *,const char * ,const char * );
char *( * get )( memcacheT *,char * );
char **( *gets )( memcacheT *,const char * );
int ( *delete ) ( memcacheT *,const char * );
int ( *add )( memcacheT *,const char *,const char * );
int ( *incr ) ( memcacheT *,const char *,int,int );
int ( *decr ) ( memcacheT *,const char *,int );
char * ip;
char * port;
int socket;
struct sockaddr_in server;
};
memcacheT * initMemcached ( const char * address );
int setCommand ( memcacheT * connection,const char * key,const char * value);
char * getCommand ( memcacheT * connection,char * key );
char ** getsmem ( memcacheT * connection,const char * keys );
int deleteCommand ( memcacheT * connection,const char * key);
int addCommand( memcacheT * connection,const char * key,const char * value);
int incrCommand ( memcacheT *connection,const char * key,int value,int flag );
int decrCommand ( memcacheT *connection,const char * key,int value );
int setCommandProcess ( memcacheT * connection,const char * key,const char * value,int flag );
#endif
#include "memcachedControl.h"
int main() {
memcacheT *connection = initMemcached("192.168.1.21:11211");
connection->set( connection,"112","i love you" );
return 0;
}