游戏项目中,设计到了一个同房间内语音相互聊天。为了跨平台,所以语音都以“.amr”保存,然后通过http的post发送到专门的amr文件管理服务器上,游戏逻辑服务器反推送给房间的每一个人,前端接收到来语音命令去请求回来响应的amr文件进行播放。
整个项目结构:
启动程序(main.go):
func main() {
fmt.Println("************************************************************")
fmt.Println("HTTPServer is worker,this port is "+conf.ServerPort+", this is running .....")
fmt.Println("************************************************************")
http.HandleFunc("/upload",worker.UploadWorker);
http.HandleFunc("/read",worker.ReadWorker);
//启动定时器 启动协程
go code.DeleteWorkerIni()
var serverListenUrl string =":"+conf.ServerPort;
http.ListenAndServe(serverListenUrl, nil );
}
上传程序(Upload.go):
func UploadWorker(w http.ResponseWriter, r *http. Request ) { ArgTokenArray,TokenState:=r.Form["token"]; ArgTimeArray,TimeState:=r.Form["time"]; if(TokenState && TimeState) { ArgToken:=ArgTokenArray[0]; ArgTime:=ArgTimeArray[0]; if(len(ArgTime)>7) { tokenStr := ArgTime[:6]+conf.ServerKey+ArgTime[6:]; //md5加密 h:=md5.New() h.Write([]byte(tokenStr)); myToken:=fmt.Sprintf("%x",h.Sum(nil)); if(myToken==ArgToken) { reader , err := r.MultipartReader(); if (err != nil) { http.Error(w, err.Error(), http.StatusInternalServerError); fmt.Println(err) return; } t := time.Now(); chartNewName := "char_" +strconv.Itoa(t.Year())+"_"+t.Month().String()+"_"+strconv.Itoa(t.Day())+"_"+strconv.FormatInt(t.UTC().UnixNano(), 10) + ".amr"; dst, _ := os.Create(conf.HomeUrl + "/data/" + chartNewName) defer dst. Close () for { part, err := reader.NextPart() if err == io.EOF { fmt.Println(err.Error()) break }else { io.Copy(dst, part); } } var reDataStr string = "{\"dataUnid\":\"" + chartNewName + "\",\"serverUrl\":\"192.168.1.4:8080\"}"; code.CharDataList[chartNewName]=t. Unix (); io.WriteString(w, reDataStr); }else { io.WriteString(w, "参数错误!"); } }else { io.WriteString(w, "参数错误!"); } }else { io.WriteString(w, "参数错误!"); } }
读取程序(Read.go):
func ReadWorker(w http.ResponseWriter,r *http.Request) {
fmt.Println("访问模式"+r.Method);
//获取客户端通过GET/POST方式传递的参数
dataUnid,dataUnidState:=r.Form["dataUnid"];
if(dataUnidState) {
fileUrl:=conf.HomeUrl + "/data/"+dataUnid[0];
_,err:=os.Stat(fileUrl);
if(err==nil){ //开始读取数据
w. Header ().Set("content-type","application/octet-stream")
fi,err:=os.Open(fileUrl);
if(err!=nil){
fmt.Println(err.Error());
return
}
defer fi.Close();
fd,err:=ioutil.ReadAll(fi);
io.WriteString(w,string(fd));
}else {
http.Error(w,"文件不存在",http.StatusInternalServerError);
}
}else {
http.Error(w,"参数错误",http.StatusInternalServerError);
}
}
管理代码(DeleteWokerIni.go):
func DeleteWorkerIni() {
timer1:=time.NewTicker(1*time.Second); //1秒钟
for{
select {
case <-timer1.C:
DelDataFileTask();
}
}
}
func DelDataFileTask() {
var nowTime =time.Now().Unix();
var deleteArray []string;
for key,createTime:= range CharDataList {
if(nowTime-conf.DataSaverTimeLen>createTime){
deleteArray= append (deleteArray, key);
}
}
if(len(deleteArray)>0){
for _,delkey:=range deleteArray{
delete(CharDataList, delkey)
//删除那个文件
del:=os.Remove(conf.HomeUrl + "/data/"+delkey);
if(del!=nil){
fmt.Println("删除文件:"+delkey)
}
}
}
}
全局变量 (GlobalData.go):
var CharDataList map[string]int64=make(map[string]int64);
配置(Conf.go):
const HomeUrl string="./httpServer" //根目录 const ServerUnid string="1" //服务器唯一编码 const ServerUrl ="192.168.1.4" //服务器ip const ServerPort string ="8080" //服务端口 const ServerKey string="L6Kjl%kBz.lhq)eqj*w3er^zl2nv*nal_s6k3#f" //服务器连接秘钥 const DataSaverTimeLen =20 //语言保存有效时间 单位秒