全平台语音服务器:iOS、Android和Windows的Golang实现
发表时间: 2019-06-10 19:42
游戏项目中,设计到了一个同房间内语音相互聊天。为了跨平台,所以语音都以“.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" //服务器ipconst ServerPort string ="8080" //服务端口const ServerKey string="L6Kjl%kBz.lhq)eqj*w3er^zl2nv*nal_s6k3#f" //服务器连接秘钥const DataSaverTimeLen =20 //语言保存有效时间 单位秒