golang文件传输服务
續(xù)上篇,本篇介紹一個(gè)完整的golang文件傳輸服務(wù)器。
完整的代碼可以看服務(wù)器,客戶端
網(wǎng)絡(luò)使用的框架如上篇介紹,這里就不再復(fù)述.
首先定義3個(gè)命令碼:
const (
request_file = 1
file_size = 2
transfering = 3
)
request_file用于請(qǐng)求文件傳輸,附帶的命令參數(shù)是文件key.
file_size用于通告客戶端文件的大小.
transfering用于傳輸文件內(nèi)容,附帶參數(shù)是文件內(nèi)容的二進(jìn)制數(shù)據(jù).
服務(wù)器的文件配置示例
../learnyouhaskell.pdf=haskell ../golang.1.1.2.chm=golang ../NodeJS.pdf=NodeJS
上面的文件配置了3個(gè)文件可供傳輸=左邊是文件路徑,右邊是請(qǐng)求文件時(shí)使用的key.
服務(wù)器啟動(dòng)時(shí)首先調(diào)用loadfile將文件導(dǎo)入到內(nèi)存中,然后根據(jù)定義的key,將文件內(nèi)容插入到字典filemap中:
func loadfile(){
//從配置導(dǎo)入文件
F,err := os.Open("./config.txt")
if err != nil {
fmt.Printf("config.txt open failed
")
return
}
filemap = make(map[string][]byte)
bufferReader := bufio.NewReader(F)
eof := false
for !eof {
line,err := bufferReader.ReadString('
')
if err == io.EOF{
err = nil
eof = true
}else if err != nil{
fmt.Printf("parse file error
")
return
}
if len(line) > 1 {
line = line[0:len(line)-1]//drop '
'
fileconfig := strings.Split(line,"=")
if len(fileconfig) == 2 {
buf, err := ioutil.ReadFile(fileconfig[0])
if err != nil {
fmt.Printf("%s load error
",fileconfig[0])
}else{
filemap[fileconfig[1]] = buf
fmt.Printf("%s load success,key %s
",fileconfig[0],fileconfig[1])
}
}
}
}
if filemap["golang"] == nil {
fmt.Printf("golang not found
")
}
fmt.Printf("loadfile finish
")
}
接著是服務(wù)其的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
")
}else
{
filename,_ := rpk.String()
filecontent := filemap[filename]
if filecontent == nil {
fmt.Printf("%s not found
",filename)
session.Close()
}else{
fmt.Printf("request file %s
",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
",cmd)
session.Close()
}
}
如果收到的消息是requestfile,首先查看請(qǐng)求的文件是否存在,如果存在則創(chuàng)建一個(gè)文件傳輸過程transfersession,
并將它與tcpsession綁定,然后發(fā)出一個(gè)文件大小通告包,緊接著立即調(diào)用send_file開始發(fā)送文件內(nèi)容.
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中根據(jù)當(dāng)前發(fā)送位置判斷還有多少內(nèi)容需要發(fā)送,如果剩余內(nèi)容小于16000字節(jié)就將所剩數(shù)據(jù)一次性
發(fā)出,否則 發(fā)送16000字節(jié)的數(shù)據(jù),并調(diào)整發(fā)送位置。注意到Send函數(shù)帶了一個(gè)sendfinish函數(shù)作為參數(shù),其作用
是當(dāng)數(shù)據(jù)包發(fā)送 完成后回調(diào)send_finish函數(shù).
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的作用是判斷文件是否已經(jīng)發(fā)送完,如果發(fā)完斷開連接,否則接著發(fā)送剩余部分.
總結(jié)一下,golang用來編寫服務(wù)器應(yīng)用還是相當(dāng)方便的,很多細(xì)節(jié)問題在語言層面或系統(tǒng)庫里已經(jīng)幫你解決掉了
,可以將主要的 精力放在邏輯的處理上.
總結(jié)
以上是生活随笔為你收集整理的golang文件传输服务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安全公司警告有黑客利用 PuTTY /
- 下一篇: 路由器串第三个路由器怎么设置家里第三个路