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;
}

Reply via email to