找回密码
 立即注册
首页 业界区 科技 MIT6.5840 2024 Spring Lab2

MIT6.5840 2024 Spring Lab2

洫伍俟 2025-6-8 22:10:49
MIT6.5840 2024 Spring Lab2

前言

  这次实验是五个实验里应该是最简单的了,这里就不多废话了,需要的知识基本和前面一样,直接根据实验要求扔思路吧。
思路

  实验要求实现能让客户端远程调用的Put()、Get()和Append(),其中Put给定key和value往服务器添加新的数据,Get根据key从服务器获取value,Append给定key和value请求服务器往key对应的value上追加字段,如果key不存在默认该key对应的字符为空字符。
  多个客户端发起请求,同一时刻只能有一个请求被处理,需要互斥访问临界资源,并且实验测试文件会模拟网络不好的情景,同一个请求可能会发送多次,所以需要唯一标识每个请求,并且本地临时存储上次请求的结果,测试文件还会检测内存使用情况,不需要的请求结果应该及时删掉,这就需要客户端收到回复后再给服务器回应确认消息。
  你可以假设每个客户端只对服务器发起一次请求,其实只需要唯一标识消息ID即可,客户端不用唯一标识,但我实现的代码也唯一标识了客户端,我是写完之后才看到这个提示,所以就默认了同一个客户端可能会多次发起请求,并且请求可能会重复。
代码实现

RPC通信消息格式
  1. //Put Append请求
  2. type PutAppendArgs struct {
  3.         Key   string
  4.         Value string
  5.         Clientid int64
  6.         Requestid int64
  7.         ReceiveFlag bool //True为回复消息
  8. }
  9. //Put Append回复
  10. type PutAppendReply struct {
  11.         Value string
  12. }
  13. //Get请求
  14. type GetArgs struct {
  15.         Key string
  16.         Clientid int64
  17.         Requestid int64
  18.         ReceiveFlag bool
  19. }
  20. //Get回复
  21. type GetReply struct {
  22.         Value string
  23. }
复制代码
Client
  1. type Clerk struct {
  2.         server *labrpc.ClientEnd
  3.         clientid int64 //增加
  4. }
  5. func MakeClerk(server *labrpc.ClientEnd) *Clerk {
  6.         ck := new(Clerk)
  7.         ck.server = server
  8.         ck.clientid = nrand()//随机产生ID号
  9.         return ck
  10. }
  11. func (ck *Clerk) Get(key string) string {
  12.         id := nrand() //消息ID随机产生
  13.         request := GetArgs{key,ck.clientid,id,false}
  14.         response := GetReply{""}
  15.         ok := false
  16.         for !ok {
  17.                 ok = ck.server.Call("KVServer.Get",&request,&response)
  18.         }
  19.         request.ReceiveFlag = true
  20.         ok = false
  21.         for !ok { //回复服务器已经接受到结果
  22.                 ok = ck.server.Call("KVServer.Get",&request,&response)
  23.         }
  24.         return response.Value
  25. }
  26. //和Get结构一样,只是改了下调用函数
  27. func (ck *Clerk) PutAppend(key string, value string, op string) string {
  28.         id := nrand()
  29.         request := PutAppendArgs{key,value,ck.clientid,id,false}
  30.         response := PutAppendReply{""}
  31.         ok := false
  32.         for !ok {
  33.                 ok = ck.server.Call("KVServer."+op,&request,&response)
  34.         }
  35.         request.ReceiveFlag = true
  36.         ok = false
  37.         for !ok {
  38.                 ok = ck.server.Call("KVServer."+op,&request,&response)
  39.         }
  40.         return response.Value
  41. }
复制代码
Server
  1. type KVServer struct {
  2.         mu sync.Mutex
  3.         keyvalue map[string]string //存储键值对
  4.         ClientLastRequest map[int64]struct{//记录还没收到回复的请求
  5.                 Requestid int64
  6.                 ReplyMsg string
  7.         }
  8. }
  9. func (kv *KVServer) Get(args *GetArgs, reply *GetReply) {
  10.         kv.mu.Lock()
  11.         defer kv.mu.Unlock()
  12.         if args.ReceiveFlag {//此消息是回复消息
  13.                 delete(kv.ClientLastRequest,args.Clientid) //删除记录
  14.                 return
  15.         }
  16.         value,ok := kv.ClientLastRequest[args.Clientid]
  17.         if ok && value.Requestid == args.Requestid { //判断是否为重复请求,如果是重复请求直接返回上次的结果
  18.                 reply.Value = value.ReplyMsg
  19.                 return
  20.         }
  21.         reply.Value = kv.keyvalue[args.Key]
  22.         kv.ClientLastRequest[args.Clientid] = struct{Requestid int64; ReplyMsg string}{args.Requestid,reply.Value}
  23.        
  24. }
  25. func (kv *KVServer) Put(args *PutAppendArgs, reply *PutAppendReply) {
  26.         kv.mu.Lock()
  27.         defer kv.mu.Unlock()
  28.         if args.ReceiveFlag {
  29.                 delete(kv.ClientLastRequest,args.Clientid)
  30.                 return
  31.         }
  32.         value,ok := kv.ClientLastRequest[args.Clientid]
  33.         if ok && value.Requestid == args.Requestid {
  34.                 reply.Value = value.ReplyMsg
  35.                 return
  36.         }
  37.         kv.keyvalue[args.Key] = args.Value
  38.         kv.ClientLastRequest[args.Clientid] = struct{Requestid int64; ReplyMsg string}{args.Requestid,""}
  39.        
  40. }
  41. func (kv *KVServer) Append(args *PutAppendArgs, reply *PutAppendReply) {
  42.         kv.mu.Lock()
  43.         defer kv.mu.Unlock()
  44.         if args.ReceiveFlag {
  45.                 delete(kv.ClientLastRequest,args.Clientid)
  46.                 return
  47.         }
  48.         value,ok := kv.ClientLastRequest[args.Clientid]
  49.         if ok && value.Requestid == args.Requestid {
  50.                 reply.Value = value.ReplyMsg
  51.                 return
  52.         }
  53.         oldvalue := kv.keyvalue[args.Key]
  54.         kv.keyvalue[args.Key] = oldvalue + args.Value
  55.         reply.Value = oldvalue
  56.         kv.ClientLastRequest[args.Clientid] = struct{Requestid int64; ReplyMsg string}{args.Requestid,oldvalue}
  57.        
  58. }
  59. func StartKVServer() *KVServer {
  60.         kv := new(KVServer)
  61.        
  62.         //初始化
  63.         kv.keyvalue = make(map[string]string)
  64.         kv.ClientLastRequest =make(map[int64]struct{Requestid int64; ReplyMsg string})
  65.         return kv
  66. }
复制代码
资料

MIT6.5840 Lab2主页

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册