简单的缓存服务器


学习unix高级编程的线程方面的内容时,写了个简单的缓存服务器。

思路:服务监听在固定端口,有客户端连接过来时,创建新线程,把连接号给该线程,由该线程负责与客户端的交互。该线程一直服务于该客户端,除非对方发出了bye的命令,(或者超时,这边没做)。真正的内容保存和获取则由专门的memserver来实现(保存时没有加锁操作)。

交互的协议为:

服务器先读,客户端先写;

客户端等待读,服务器处理上一步获取的命令;

服务返回命令处理结果。


内容格式:

头三个字节:命令;

接着2个字节:整个包长度;

接着字节是内容;

接着1字节:key长度

接着字节是key内容

接着2字节:内容长度

接着是内容


服务端:——————————————————————

/** memserver.h **/

struct InterCont{
  char* key;
  char* content;
};




struct Meta{
  char* key;
  int keyLen;
  int readCount;
  int contLen;
  struct InterCont* realContent;
  struct Meta* next;
};


struct entry{
  int count;
  struct Meta* meta;
};




int save(const struct InterCont* val);


int del(const char* key);


struct InterCont* get(const char* key);


void printMemInfo();


void printInterCont(const struct InterCont* cont);



/**         memserver.c   **/

#include "memserver.h"
#include <stdio.h>
#define ENTRY_CNT 20


//entry for record
struct entry *memEntry[ENTRY_CNT];




//memory info
long entryPointMemInByte=0;
long metaMemInByte=0;
long contentMemInByte=0;


int hash(const char key[]){
  char one;
  int sum=0;
  int i=0;


  one=key[0];
  printf("-------------\n%c",one);
  i=1;
  while(one!='\0'){
       sum+=(int)one;
       one=key[i++];
       printf("%c",one);
  }
  printf("\nsum=%d\n----------------",sum);
 return  sum % ENTRY_CNT;
}


int del(const char* key){
  printf("del key=%s\n",key);
}


int save(const struct InterCont* val){
 printf("save one ....");
// printInterCont(val); 
 if(val==NULL){
    return 0;
  }
  int hk=hash(val->key);
  printf("save %s , hash key=%d\n",val->key,hk);
  struct entry* et=memEntry[hk];
  


  printf("prepare content memory...\n");
   //alloc content
  struct InterCont* newone=(struct InterCont*)malloc(sizeof(struct InterCont));
    
   newone->key=val->key;
   newone->content=val->content;
  
  printf("prepare meta...\n");
   //meta
   struct Meta* meta=(struct Meta*)malloc(sizeof(struct Meta));
   meta->key=val->key;
   meta->keyLen=strlen(val->key);
   meta->readCount=0;
   meta->contLen=strlen(val->content);
   meta->realContent=newone;
   meta->next=NULL;






  if(et!=NULL){
    printf("hk=%d has alreay as least store one content!will extend its meta list !\n"); 
    //find the last meta
    struct Meta* inchain=et->meta;
    //iterate until the last or encount same key
    while(inchain->next!=NULL && strcmp(inchain->key,val->key)){
       inchain=inchain->next;
    };


    //if key already exists
    if(strcmp(inchain->key,val->key)==0){
        printf("save key:%s already exist!will replace old value with the new one!\n",val->key);
free(inchain->realContent->content);
inchain->realContent->content=malloc(strlen(val->content)+1);
strcpy(inchain->realContent->content,val->content);
free(meta);
    }
    else{
    inchain->next=meta;
    et->count++;
    }
  }else{
   //entry is empty ,so use it
   printf("save , first use entry %d\n",hk);


   et=(struct entry*)malloc(sizeof(struct entry));
   memEntry[hk]=et;
   et->count=1;
   et->meta=meta;
   
   //incre entry mem info
   entryPointMemInByte+=sizeof(struct entry);
  }
  printf("finished save!\n");


  //refresh memory info
  
  return 1;
}


struct InterCont* get(const char* key){
  int hk=hash(key);
  struct entry* one= memEntry[hk];
  if(one!=NULL){
     int cnt=one->count;
     if(cnt>1){
        printf("hk=%d has more then one value:%d\n",hk,cnt);
     }
     struct Meta* meta=one->meta;
     if(meta==NULL){
        printf("error!no meta data found!hk=%d\n",hk);
        return NULL;
     }
     struct InterCont* ret=NULL;
     int keylen=strlen(key);
     do{
        if(meta->keyLen==keylen){
         char* cmpkey=meta->key;
if(strcmp(cmpkey,key)==0){
            ret=meta->realContent;
   meta->readCount++;
   return ret;
}
        }
         
        meta=meta->next;


     }while(meta!=NULL);
  }
  return NULL;
}


int getMetaSize(struct Meta* meta){
 int sum=0;
 sum+=sizeof(struct Meta);
 sum+=strlen(meta->key)+1;
 return sum;
}


long getInterContSize(struct InterCont* cont){
 long sum=0;
 sum+=sizeof(struct InterCont);
 sum+=strlen(cont->key)+1;
 sum+=strlen(cont->content)+1;


 return sum;


}


void printOneMeta(struct Meta* mt){


  printf("--------------------print meta  begin---------------\n");
  printf("meta key=%s,readCount=%d\n",mt->key,mt->readCount);
  printf("content=%s\n",mt->realContent->content);
  printf("--------------------print meta  end ---------------\n");
}




void printOneEntry(struct entry* ent){
  printf("--------------print entry begin---------------\n");
  printf("entry count=%d\n",ent->count);
  struct Meta* mt=ent->meta;
  while(mt!=NULL){
      printOneMeta(mt);
      mt=mt->next;
  }
  
  printf("--------------print entry end---------------\n");
}


void printMemInfo(){
 printf("\n--------printMemInfo begin-------------------\n");
 int i=0;
 for(;i<ENTRY_CNT;i++){
    if(memEntry[i]!=NULL){
         printOneEntry(memEntry[i]);
    }
 }
 printf("--------printMemInfo end  -------------------\n");
}






void printInterCont(const struct InterCont* cont){
   if(cont==NULL){
        printf("empty cont!\n");
        return;
   }
   else{
        printf("InterCont info[key=%s,cont=%s\n",cont->key,cont->content);
   }
}




//void main(){
/*
  char key[]="ha";
  key[sizeof(key)]='\0';
  


  char* fp=key;
  int hk=hash(key);
 
  printf("key len=%d,hash value of  key: \'%s\' is %d\n",strlen(key),key,hk);
  


  printf("sizefo IntentCont is %d\n",sizeof(struct InterCont));
*/
 /*
 struct InterCont* pp=(struct InterCont*)malloc(sizeof(struct InterCont));


  pp->key="ha";
  pp->content="a person's info";
  
  int res=save(pp);
  printf("save ret=%d\n",res);
  struct InterCont* mid=get(pp->key);
  printf("try to print result get from cache..\n");
  printInterCont(mid);
 
  pp=(struct InterCont*)malloc(sizeof(struct InterCont));
  pp->key="ah";
  pp->content="another info";
  res=save(pp);
  printf("save ret=%d\n",res);
  mid=get(pp->key);
  printInterCont(mid);


}*/



/** ------------------server.c-------------------------**/

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>


#include "memserver.h"


/*

将字节流翻译为格式内容

*/
void decodeStream(struct InterCont* intercont,char* buf){
       //struct InterCont* intercont=malloc(sizeof(struct InterCont));


       char cmd[4];
       char *key;
       int bufIndex;


       char *content;


       int i,j,k;
       //cmd
       strncpy(cmd,buf,3);
       cmd[3]='\0';
       printf("get cmd:%s\n",cmd);
       
       //key
       int keylen;
       keylen=(int)buf[3];
       printf("get keylen=%d\n",keylen);
      
       bufIndex=4;
       if(keylen>0){
         key=malloc(keylen+1);
for(i=0;i<keylen;i++){
            key[i]=buf[bufIndex++];
}
key[i]='\0';
printf("key is %s\n",key);
       }
       intercont->key=key;


       //content
       bufIndex++;
       bufIndex++;


       printf("bufIndex=%d,strlen(buf)=%d\n",bufIndex,strlen(buf));
       if(bufIndex<strlen(buf)){
            content=malloc(strlen(buf)-bufIndex+1); 
   i=0;
            while(bufIndex<strlen(buf)){
                content[i++]=buf[bufIndex++];
   }
   content[i++]='\0';
   printf("content is %s\n",content);
   intercont->content=content;
       }else{
          intercont->content=NULL;
          printf("no content!");
       }
       if(key!=NULL){
       //    free(key);
       }
       if(content!=NULL){
         //  free(content);
       }
      
}




//thread function
void * doconnect(void *arg){


int client=*((int *)arg);
printf("do connect ,client=%d\n",client);
        char buf[1024];
int len;
char cmd[4];
char* content;
char *key;
int keylen;
int contentlen;
        
struct InterCont* interCont;
int i,j;
        while(1){
       len=read(client,buf,1024);
buf[len]='\0';
fputs(buf,stdout);
        
char *ret;
        if(strncmp(buf,"bye",3)==0){
            printf("client try to close socket\n");
  ret="i will close too";
            write(client,ret,strlen(ret));
  close(client);
  pthread_exit((void*)0);
}else if(strncmp(buf,"bad",3)==0){
                        printf("client send bad cmd\n");
ret="bad cmd";
write(client,ret,strlen(ret));
}
else{
/*        if(key!=NULL){
                            free(key);
}
if(content!=NULL){
   free(content);
}
*/


ret="i have handle your request.";
//cmd,first 3 byte
                        strncpy(cmd,buf,3);
cmd[3]='\0';
printf("get cmd from client:%s,len=%d\n",cmd,strlen(cmd));
struct InterCont intercont;
//decode
                        decodeStream(&intercont,buf);
                        //get
if(strncmp(cmd,"get",3)==0){
                            //get key
                           interCont=get(intercont.key);
  printInterCont(interCont);
  if(interCont!=NULL){
  write(client,interCont->content,strlen(interCont->content));
  }else{
                                 write(client,"null",4);
  }
}
//
//sav
else if(strncmp(cmd,"sav",3)==0){
                             i=save(&intercont);
    printf("save res=%d\n",i);
    if(i==1){
                               write(client,"save ok",7);
    }else{
                               write(client,"save fail!",10);
    }
}
//
//del
else if(strncmp(cmd,"del",3)==0){
                             del(intercont.key);
                             write(client,"del ok",5);
                        }
//print mem info
else if(strncmp(cmd,"prt",3)==0){
                             printMemInfo();
    write(client,"print ok",8);
}
else{
    printf("unknow command!%s\n",cmd);
                             ret="unknown command.";
            write(client,ret,strlen(ret));
}


        }
}
}








int main(int argc,char* args[]){
         
if(argc!=2){
              printf("usage:server 192.168.x.xx\n");
     exit(-3);
}
struct sockaddr_in s_sock_addr,c_sock_addr;


        int addr_size;
int s_fp,c_fp;
int port=0x1666;//固定端口
        int bindres;


        //construct
s_fp=socket(AF_INET,SOCK_STREAM,0);
        if(s_fp==-1){
            printf("fail to construct sock!\n");
   exit(-1);
}
printf("after construct sock....\n");


//bind
bzero(&s_sock_addr,sizeof(struct sockaddr_in));
printf("ip addr:%s\n",args[1]);
s_sock_addr.sin_family=AF_INET;
s_sock_addr.sin_addr.s_addr=inet_addr(args[1]);
s_sock_addr.sin_port=htons(port);
        
        bindres=bind(s_fp,(struct sockaddr*)(&s_sock_addr),sizeof(struct sockaddr));
        if(bindres!=0){
            printf("error bind!%s\n",strerror(bindres));
   exit(1);
}
        printf("after bind sock ... \n");


        //listen
if(listen(s_fp,5)==-1){
           printf("fail to listen!\n");
  exit(2);
}
        printf("after listen ....\n");
        
pthread_t tid;
int err;
        while(1){
               printf("in loop.....\n");
               addr_size=sizeof(struct sockaddr_in);
               c_fp=accept(s_fp,(struct sockaddr*)(&c_sock_addr),&addr_size);
      if(c_fp==-1){
                    printf("accept fail!\n");
   exit(3);
      }
      printf("get one client connect.cfp=%d ... \n",c_fp);
               
      //new thread
     err= pthread_create(&tid,NULL,doconnect,&c_fp);//交给工作线程
     if(err!=0){
                printf("fail to create thread!%s\n",strerror(err));
                close(c_fp);
continue;
     }
     
};
}


/**——————Makefile————————*/

main:server.o memserver.o
cc -o main server.o memserver.o -lpthread
server.o:server.c memserver.h
cc -c server.c
memserver.o:memserver.c
cc -c memserver.c
clean:
-rm *.o



//-----------------------------------------客户端-----------------------------------------------------//

/**-----client.c--------------*/

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>




char data[1024];


//format   use input to meet the   procotol requirement
char* makestream(char* buf){
    //char data[1024];
    char cmd[4];
    char* key;
    int keylen;
    
    strncpy(cmd,buf,3);
    cmd[3]='\0';


    strncpy(data,buf,3);//copy cmd
    //key
    int i=3,j=0,k=0;
    int dataIndex=0;


    if(buf[i]!=' '){
        printf("usage:cmd key attachdata\n");
        strncpy(data,"bad",3);
data[3]='\0';
return data;
    }
    i=4;
    char tempkey[512];
    j=0;
    while(buf[i]!=' '&&buf[i]!='\n'){
       tempkey[j++]=buf[i++];
    }
    tempkey[j]='\0';
    keylen=strlen(tempkey);
    printf("key is %s,kenlen=%d\n",tempkey,keylen);
    data[3]=keylen;
    dataIndex=4;
    for(k=0;k<j;k++){
      data[dataIndex++]=tempkey[k];
    }
    //if content is need
    if(strncmp(cmd,"sav",3)==0){
        printf("need content\n");
if(buf[i]!=' '){
 printf("cmd %s need content,but not found!\n",cmd);
          strncpy(data,"bad",3);
 return data;
}
i++;
char tempcontent[1024];
j=0;
while(buf[i]!='\n'){
            tempcontent[j++]=buf[i++];
}
if(j==0){
             printf("cmd %s without content!\n",cmd);
    strncpy(data,"bad",3);
    return data;
}




//content len
data[dataIndex++]='0';
data[dataIndex++]='0';
for(k=0;k<j;k++){
           data[dataIndex++]=tempcontent[k];
}
    }else{
          data[dataIndex++]=0;//just set the key len with 0
    }


    data[dataIndex++]='\0';//last char is terminal char
    printf("data is %s\n",data);
return data;


}


struct InterCont* decodeStream(char* buf){
       //struct InterCont* intercont=malloc(sizeof(struct InterCont));


       char cmd[4];
       char *key;
       int bufIndex;


       char *content;


       int i,j,k;
       //cmd
       strncpy(cmd,buf,3);
       cmd[3]='\0';
       //intercont->key=cmd;
       printf("get cmd:%s\n",cmd);
       
       //key
       int keylen;
       keylen=(int)buf[3];
       printf("get keylen=%d\n",keylen);
      
       bufIndex=4;
       if(keylen>0){
         key=malloc(keylen+1);
for(i=0;i<keylen;i++){
            key[i]=buf[bufIndex++];
}
key[i]='\0';
printf("key is %s\n",key);
       }


       //content
       bufIndex++;
       bufIndex++;


       printf("bufIndex=%d,strlen(buf)=%d\n",bufIndex,strlen(buf));
       if(bufIndex<strlen(buf)){
            content=malloc(strlen(buf)-bufIndex+1); 
   i=0;
            while(bufIndex<strlen(buf)){
                content[i++]=buf[bufIndex++];
   }
   content[i++]='\0';
   printf("content is %s\n",content);
       }else{
          printf("no content!");
       }
       if(key!=NULL){
       //    free(key);
       }
       if(content!=NULL){
         //  free(content);
       }
       return NULL;


}




void main(){


        char buf[1024];
char one;
char *res;


         
        int port=0x1666;
        struct sockaddr_in s_sock_addr;
        int c_sock;


c_sock=socket(AF_INET,SOCK_STREAM,0);
if(c_sock==-1){
             printf("fail to construct client sock!\n");
    exit(1);
}

bzero(&s_sock_addr,sizeof(struct sockaddr_in));
s_sock_addr.sin_family=AF_INET;
s_sock_addr.sin_addr.s_addr=inet_addr("192.168.1.105");
s_sock_addr.sin_port=htons(port);


        
//connect
if(connect(c_sock,(struct sockaddr*)(&s_sock_addr),sizeof(struct sockaddr))==-1){
           printf("fail to connect to server!\n");
  exit(5);
}
        
        int len=0;
        char ret[1024];
//loop,get cmd
while(1){
   //printf("please input sth...\n");
                     
   res=fgets(buf,1024,stdin);
   if(strncmp(buf,"quit",4)==0 || strncmp(buf,"bye",3)==0){
       char* bye="bye";
       write(c_sock,bye,3);
read(c_sock,ret,sizeof(ret));
                break;
   }
   if(strlen(buf)==1){
                continue;
   }
   printf("length=%d\n",strlen(buf));
   fputs(res,stdout);
            
   //write to server
   char *data=makestream(buf);
            if(strncmp(data,"bad",3)==0){
               printf("bad command!\n");
      continue;
   }
           
    // write to server
   write(c_sock,data,strlen(data));


            
   
   len=read(c_sock,ret,sizeof(ret));
   ret[len]='\0';
   printf("return from server:%s\n",ret);
   
};
        close(c_sock);
}

/*** Makefile */

client:client.o
cc -o client client.o
client.o:client.c
cc -c client.c
clean:
-rm *.o client



下一步,学习一下当前的缓存服务器的源码,提高一下这方面的知识,再完善一下。特别是内存管理方面(申请,回收,如果提高效率)、内容持久化,同步方面,连接队列,等等。

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值