分享
  1. 首页
  2. 文章

golang文件传输服务

sniperHW · · 9564 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

续上篇,本篇介绍一个完整的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中:

func loadfile(){
 //从配置导入文件
 F,err := os.Open("./config.txt")
 if err != nil {
 fmt.Printf("config.txt open failed\n")
 return
 }
 filemap = make(map[string][]byte)
 bufferReader := bufio.NewReader(F)
 eof := false
 for !eof {
 line,err := bufferReader.ReadString('\n')
 if err == io.EOF{
 err = nil
 eof = true
 }else if err != nil{
 fmt.Printf("parse file error\n")
 return
 }
 if len(line) > 1 {
 line = line[0:len(line)-1]//drop '\n'
 fileconfig := strings.Split(line,"=")
 if len(fileconfig) == 2 {
 buf, err := ioutil.ReadFile(fileconfig[0])
 if err != nil {
 fmt.Printf("%s load error\n",fileconfig[0])
 }else{ 
 filemap[fileconfig[1]] = buf
 fmt.Printf("%s load success,key %s\n",fileconfig[0],fileconfig[1])
 }
 }
 }
 }
 if filemap["golang"] == nil {
 fmt.Printf("golang not found\n")
 }
 fmt.Printf("loadfile finish\n") 
}

接着是服务其的packet_handler:

func process_client(session *tcpsession.Tcpsession,rpk *packet.Rpacket){
 cmd,_ := rpk.Uint16()
 if cmd == request_file {
 if session.Ud() != nil {
 fmt.Printf("already in transfer session\n")
 }else
 {
 filename,_ := rpk.String()
 filecontent := filemap[filename]
 if filecontent == nil {
 fmt.Printf("%s not found\n",filename)
 session.Close()
 }else{
 fmt.Printf("request file %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("cmd error,%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
 if remain >= 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函数.

func send_finish (s interface{},wpk *packet.Wpacket){
 session := s.(*tcpsession.Tcpsession)
 tsession := session.Ud().(*transfer_session)
 if tsession.check_finish(){
 session.Close()
 return
 }
 tsession.send_file(session)
}

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

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

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


有疑问加站长微信联系(非本文作者)

本文来自:博客园

感谢作者:sniperHW

查看原文:golang文件传输服务

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
9564 次点击 ∙ 1 赞
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏