洫伍俟 发表于 2025-6-8 22:10:49

MIT6.5840 2024 Spring Lab2

MIT6.5840 2024 Spring Lab2

前言

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

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

RPC通信消息格式

//Put Append请求
type PutAppendArgs struct {
        Key   string
        Value string
        Clientid int64
        Requestid int64
        ReceiveFlag bool //True为回复消息
}
//Put Append回复
type PutAppendReply struct {
        Value string
}
//Get请求
type GetArgs struct {
        Key string
        Clientid int64
        Requestid int64
        ReceiveFlag bool
}
//Get回复
type GetReply struct {
        Value string
}Client

type Clerk struct {
        server *labrpc.ClientEnd
        clientid int64 //增加
}
func MakeClerk(server *labrpc.ClientEnd) *Clerk {
        ck := new(Clerk)
        ck.server = server
        ck.clientid = nrand()//随机产生ID号
        return ck
}
func (ck *Clerk) Get(key string) string {

        id := nrand() //消息ID随机产生
        request := GetArgs{key,ck.clientid,id,false}
        response := GetReply{""}
        ok := false
        for !ok {
                ok = ck.server.Call("KVServer.Get",&request,&response)
        }
        request.ReceiveFlag = true
        ok = false
        for !ok { //回复服务器已经接受到结果
                ok = ck.server.Call("KVServer.Get",&request,&response)
        }
        return response.Value
}

//和Get结构一样,只是改了下调用函数
func (ck *Clerk) PutAppend(key string, value string, op string) string {
        id := nrand()
        request := PutAppendArgs{key,value,ck.clientid,id,false}
        response := PutAppendReply{""}
        ok := false
        for !ok {
                ok = ck.server.Call("KVServer."+op,&request,&response)
        }
        request.ReceiveFlag = true
        ok = false
        for !ok {
                ok = ck.server.Call("KVServer."+op,&request,&response)
        }
        return response.Value
}Server

type KVServer struct {
        mu sync.Mutex
        keyvalue mapstring //存储键值对
        ClientLastRequest mapstruct{//记录还没收到回复的请求
                Requestid int64
                ReplyMsg string
        }
}
func (kv *KVServer) Get(args *GetArgs, reply *GetReply) {
        kv.mu.Lock()
        defer kv.mu.Unlock()
        if args.ReceiveFlag {//此消息是回复消息
                delete(kv.ClientLastRequest,args.Clientid) //删除记录
                return
        }
        value,ok := kv.ClientLastRequest
        if ok && value.Requestid == args.Requestid { //判断是否为重复请求,如果是重复请求直接返回上次的结果
                reply.Value = value.ReplyMsg
                return
        }
        reply.Value = kv.keyvalue
        kv.ClientLastRequest = struct{Requestid int64; ReplyMsg string}{args.Requestid,reply.Value}
       
}
func (kv *KVServer) Put(args *PutAppendArgs, reply *PutAppendReply) {
        kv.mu.Lock()
        defer kv.mu.Unlock()
        if args.ReceiveFlag {
                delete(kv.ClientLastRequest,args.Clientid)
                return
        }
        value,ok := kv.ClientLastRequest
        if ok && value.Requestid == args.Requestid {
                reply.Value = value.ReplyMsg
                return
        }
        kv.keyvalue = args.Value
        kv.ClientLastRequest = struct{Requestid int64; ReplyMsg string}{args.Requestid,""}
       
}
func (kv *KVServer) Append(args *PutAppendArgs, reply *PutAppendReply) {
        kv.mu.Lock()
        defer kv.mu.Unlock()
        if args.ReceiveFlag {
                delete(kv.ClientLastRequest,args.Clientid)
                return
        }
        value,ok := kv.ClientLastRequest
        if ok && value.Requestid == args.Requestid {
                reply.Value = value.ReplyMsg
                return
        }
        oldvalue := kv.keyvalue
        kv.keyvalue = oldvalue + args.Value
        reply.Value = oldvalue
        kv.ClientLastRequest = struct{Requestid int64; ReplyMsg string}{args.Requestid,oldvalue}
       
}
func StartKVServer() *KVServer {
        kv := new(KVServer)
       
        //初始化
        kv.keyvalue = make(mapstring)
        kv.ClientLastRequest =make(mapstruct{Requestid int64; ReplyMsg string})
        return kv
}资料

MIT6.5840 Lab2主页

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: MIT6.5840 2024 Spring Lab2