首页 文章资讯内容详情

golang文件传输服务

2026-06-01 3 花语

本文内容纲要:

续上篇,本篇介绍一个完整的golang文件传输服务器。

完整的代码可以看服务器,客户端

网络使用的框架如上篇介绍,这里就不再复述.

首先定义3个命令码:

const( request_file=1 file_size=2 transfering=3 )

request_file用于请求文件传输,附带的命令参数是文件key.

file_size用于通告客户端文件的大小.

transfering用于传输文件内容,附带参数是文件内容的二进制数据.

服务器的文件配置示例

../learnyouhaskell.pdf=haskell ../golang.1.1.2.chm=golang ../NodeJS.pdf=NodeJS

上面的文件配置了3个文件可供传输=左边是文件路径,右边是请求文件时使用的key.

服务器启动时首先调用loadfile将文件导入到内存中,然后根据定义的key,将文件内容插入到字典filemap中:

funcloadfile(){ //从配置导入文件 F,err:=os.Open("./config.txt") iferr!=nil{ fmt.Printf("config.txtopenfailed\n") return } filemap=make(map[string][]byte) bufferReader:=bufio.NewReader(F) eof:=false for!eof{ line,err:=bufferReader.ReadString(\n) iferr==io.EOF{ err=nil eof=true }elseiferr!=nil{ fmt.Printf("parsefileerror\n") return } iflen(line)>1{ line=line[0:len(line)-1]//drop\n fileconfig:=strings.Split(line,"=") iflen(fileconfig)==2{ buf,err:=ioutil.ReadFile(fileconfig[0]) iferr!=nil{ fmt.Printf("%sloaderror\n",fileconfig[0]) }else{ filemap[fileconfig[1]]=buf fmt.Printf("%sloadsuccess,key%s\n",fileconfig[0],fileconfig[1]) } } } } iffilemap["golang"]==nil{ fmt.Printf("golangnotfound\n") } fmt.Printf("loadfilefinish\n") }

接着是服务其的packet_handler:

funcprocess_client(session*tcpsession.Tcpsession,rpk*packet.Rpacket){ cmd,_:=rpk.Uint16() ifcmd==request_file{ ifsession.Ud()!=nil{ fmt.Printf("alreadyintransfersession\n") }else { filename,_:=rpk.String() filecontent:=filemap[filename] iffilecontent==nil{ fmt.Printf("%snotfound\n",filename) session.Close() }else{ fmt.Printf("requestfile%s\n",filename) tsession:=&transfer_session{filecontent:filecontent,ridx:0} session.SetUd(tsession) wpk:=packet.NewWpacket(packet.NewByteBuffer(64),false) wpk.PutUint16(file_size) wpk.PutUint32(uint32(len(filecontent))) session.Send(wpk,nil) tsession.send_file(session) } } }else{ fmt.Printf("cmderror,%d\n",cmd) session.Close() } }

如果收到的消息是requestfile,首先查看请求的文件是否存在,如果存在则创建一个文件传输过程transfersession,

并将它与tcpsession绑定,然后发出一个文件大小通告包,紧接着立即调用send_file开始发送文件内容.

func(this*transfer_session)send_file(session*tcpsession.Tcpsession){ remain:=len(this.filecontent)-this.ridx sendsize:=0 ifremain>=16000{ sendsize=16000 }else{ sendsize=remain } wpk:=packet.NewWpacket(packet.NewByteBuffer(uint32(sendsize)),false) wpk.PutUint16(transfering) wpk.PutBinary(this.filecontent[this.ridx:this.ridx+sendsize]) session.Send(wpk,send_finish) this.ridx+=sendsize }

sendfile中根据当前发送位置判断还有多少内容需要发送,如果剩余内容小于16000字节就将所剩数据一次性

发出,否则发送16000字节的数据,并调整发送位置。注意到Send函数带了一个sendfinish函数作为参数,其作用

是当数据包发送完成后回调send_finish函数.

funcsend_finish(sinterface{},wpk*packet.Wpacket){ session:=s.(*tcpsession.Tcpsession) tsession:=session.Ud().(*transfer_session) iftsession.check_finish(){ session.Close() return } tsession.send_file(session) }

send_finish的作用是判断文件是否已经发送完,如果发完断开连接,否则接着发送剩余部分.

总结一下,golang用来编写服务器应用还是相当方便的,很多细节问题在语言层面或系统库里已经帮你解决掉了

,可以将主要的精力放在逻辑的处理上.

本文内容总结:

原文链接:https://www.cnblogs.com/sniperHW/p/3587313.html