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]