Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7389204
  • 博文数量: 1755
  • 博客积分: 18684
  • 博客等级: 上将
  • 技术积分: 16227
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-02 10:28
个人简介

啥也没写

文章分类

全部博文(1755)

文章存档

2024年(1)

2023年(44)

2022年(39)

2021年(46)

2020年(43)

2019年(27)

2018年(44)

2017年(50)

2016年(47)

2015年(15)

2014年(21)

2013年(43)

2012年(143)

2011年(228)

2010年(263)

2009年(384)

2008年(246)

2007年(30)

2006年(38)

2005年(2)

2004年(1)

分类: LINUX

2012-04-24 09:02:54

前言:最近学习Go语言 尝试写了一个简单的文件同步,基于tcp的,功能比较简单。基于Go version 1 编译。

该程序的功能:


  1. 只能传输单一文件,文件名不能有特殊符号和空格
  2. 有serve端和client命令 使用同一个程序
  3. 不能同步目录结构
  4. 不能改名字
  5. 无法查看进度

该程序主要就是将指定的文件同步到新的服务器和指定的目录下面,并且该文件的时间和属性跟原来一样,可以使用rsync进行检测。

该程序名字 gosync

gosync.go


点击(此处)折叠或打开

  1. package main

  2. import (
  3.     "os"
  4.     "fmt"
  5.     "net"
  6.     "flag"
  7.     "time"
  8.     "crypto/md5"
  9.     "io"
  10.     "strings"
  11.     "strconv"
  12. )

  13. type sysFileInfo struct{
  14.     fName string
  15.     fSize int64
  16.     fMtime time.Time
  17.     fPerm os.FileMode
  18.     fMd5 string
  19.     fType bool
  20. }

  21. var (
  22.     listenPort = flag.String( "port","7722","server listen port" )
  23.     syncFile = flag.String( "file","","transfer file" )
  24.     syncHost = flag.String( "host","","server host" )
  25.     syncSer = flag.Bool( "d",false,"server mode")
  26.     syncFold = flag.String( "dir","/tmp/gosync/","recive sync fold ")
  27. )

  28. func main(){
  29.     flag.Parse()
  30.     if *syncSer {
  31.         servPort:=fmt.Sprintf( ":%s",*listenPort )
  32.         l,err := net.Listen( "tcp",servPort )
  33.         if err != nil{
  34.            fmt.Println( "net failed",err )
  35.         }
  36.         err = os.MkdirAll( *syncFold , 0755)
  37.         if err != nil{
  38.            fmt.Println( err )
  39.         }
  40.         fmt.Println( "Start Service" )
  41.         Serve( l )
  42.      }else{
  43.         destination:=fmt.Sprintf( "%s:%s",*syncHost,*listenPort )
  44.         clientSend( *syncFile,destination)
  45.      }
  46. }

  47. func clientSend(files string,destination string){
  48.     fInfo:=getFileInfo( files)
  49.     newName :=fmt.Sprintf( "%s",fInfo.fName)
  50.     cmdLine:= fmt.Sprintf( "upload %s %d %d %d %s " ,newName,fInfo.fMtime.Unix(),fInfo.fPerm,fInfo.fSize,fInfo.fMd5)
  51.     cn,err:=net.Dial( "tcp", destination)
  52.     if err !=nil {
  53.         fmt.Println( "connect error",err )
  54.         return
  55.     }
  56.     defer cn.Close()
  57.     cn.Write( []byte( cmdLine ) )
  58.     cn.Write( []byte( "\r\n" ) )
  59.     fileHandle,err := os.Open( files )
  60.     if err != nil {
  61.         fmt.Println("open ERROR",err)
  62.         return
  63.     }
  64.     io.Copy( cn,fileHandle)
  65.     for{
  66.         buffer :=make( []byte,1024)
  67.         num,err := cn.Read(buffer)
  68.         if err == nil && num > 0{
  69.             fmt.Println( string(buffer[ :num ]) )
  70.             break
  71.         }
  72.     }
  73. }

  74. func getFileInfo( filename string) *sysFileInfo{
  75.     fi,err:= os.Lstat( filename )
  76.     if err != nil {
  77.         fmt.Println("info ERROR",err)
  78.         return nil
  79.     }
  80.     fileHandle,err := os.Open( filename )
  81.     if err != nil {
  82.         fmt.Println("open ERROR",err)
  83.         return nil
  84.     }

  85.     h := md5.New()
  86.     _,err = io.Copy( h,fileHandle )
  87.     fileInfo := & sysFileInfo {
  88.         fName : fi.Name(),
  89.         fSize : fi.Size(),
  90.         fPerm : fi.Mode().Perm(),
  91.         fMtime: fi.ModTime(),
  92.         fType : fi.IsDir(),
  93.         fMd5 : fmt.Sprintf( "%x", h.Sum( nil )),
  94.     }
  95.         return fileInfo
  96. }

  97. func Serve( l net.Listener) {
  98.     for{
  99.         conn,err := l.Accept()
  100.         if err != nil{
  101.             if ne,ok := err.( net.Error );ok && ne.Temporary(){
  102.                 continue
  103.             }
  104.             fmt.Println( "network error",err )
  105.         }
  106.         go Handler(conn)
  107.     }
  108. }

  109. func Handler( conn net.Conn) {
  110.     defer conn.Close()
  111.     state := 0
  112.     var cmd *sysFileInfo
  113.     var fSize int64
  114.     var tempFileName string
  115.     var n int64
  116.     for {
  117.         buffer :=make( []byte,2048)
  118.         num,err := conn.Read(buffer)
  119.         numLen:=int64( num )
  120.         if err != nil && err != io.EOF {
  121.             fmt.Println( "cannot read",err )
  122.         }
  123.         n=0
  124.         if state == 0 {
  125.             n,cmd = cmdParse( buffer[:num] )
  126.             tempFileName = fmt.Sprintf( "%s.newsync",cmd.fName)
  127.             fSize = cmd.fSize
  128.             state = 1
  129.         }
  130.         if state == 1 {
  131.             last := numLen
  132.             if fSize <= numLen-n {
  133.                 last = fSize + n
  134.                 state = 2
  135.             }
  136.             err = writeToFile( buffer[int( n ):int( last )],tempFileName,cmd.fPerm )
  137.             if err != nil{
  138.                 fmt.Println( "read num error : ",err )
  139.             }
  140.             fSize -=last-n
  141.             if state == 2{
  142.                 os.Remove( cmd.fName)
  143.                 err = os.Rename( tempFileName,cmd.fName)
  144.                 if err != nil{
  145.                     fmt.Println( "rename ",tempFileName," to ",cmd.fName," failed" )
  146.                 }
  147.                 err = os.Chtimes( cmd.fName,time.Now(),cmd.fMtime )
  148.                 if err != nil{
  149.                     fmt.Println( "change the mtime error ",err )
  150.                 }
  151.                 fileHandle,err := os.Open( cmd.fName)
  152.                 if err != nil {
  153.                     fmt.Println("open ERROR",err)
  154.                 }
  155.                 h := md5.New()
  156.                 io.Copy( h,fileHandle )
  157.                 newfMd5 := fmt.Sprintf( "%x", h.Sum( nil ))
  158.                 if newfMd5 == cmd.fMd5{
  159.                     sendInfo:=fmt.Sprintf("%s sync success",cmd.fName)
  160.                     conn.Write([]byte(sendInfo))
  161.                 }else{
  162.                     sendInfo:=fmt.Sprintf("%s sync failed",cmd.fName)
  163.                     conn.Write([]byte(sendInfo))
  164.                 }
  165.             }
  166.         }
  167.     }
  168. }

  169. func cmdParse( infor []byte) ( int64 , *sysFileInfo) {
  170.     var i int64
  171.     for i=0;i<int64(len(infor));i++ {
  172.        if infor[i] == '\n' && infor[i-1] == '\r' {
  173.            cmdLine:=strings.Split( string( infor[:i-1] ) ," ")
  174.            fileName := fmt.Sprintf( "%s/%s",*syncFold,cmdLine[ 1 ] )
  175.            filePerm, _ := strconv.Atoi( cmdLine[ 3 ])
  176.            fileMtime,_:= strconv.ParseInt( cmdLine[ 2 ],10,64 )
  177.            fileSize,_:= strconv.ParseInt( cmdLine[ 4 ],10,64)
  178.            fileInfo := & sysFileInfo {
  179.                 fName : fileName,
  180.                 fMtime: time.Unix( fileMtime,0 ),
  181.                 fPerm : os.FileMode(filePerm),
  182.                 fSize : fileSize,
  183.                 fMd5 : string(cmdLine[ 5 ]),
  184.            }
  185.            return i+1,fileInfo
  186.        }
  187.     }
  188.        return 0,nil
  189. }

  190. func writeToFile( data []byte ,fileName string,perm os.FileMode) error{
  191.     writeFile,err := os.OpenFile( fileName,os.O_RDWR | os.O_APPEND | os.O_CREATE ,perm)
  192.     if err != nil{
  193.         fmt.Println( "write file error:",err )
  194.         return err
  195.     }
  196.     defer writeFile.Close()
  197.     _,err = writeFile.Write( data )
  198.     if err != nil{
  199.        fmt.Println( "write file error",err )
  200.        return err
  201.     }
  202.     return nil
  203. }

使用:

usage:
Usage of ./gosync:
  -d=false: server mode
  -dir="/tmp/gosync/": recive sync fold
  -file="": transfer file
  -host="": server host
  -port="7722": server listen port
服务端开启

#./gosync -d -dir /tmp/xxxx

client传输文件:
# ./gosync --file=/root/Videos/DSCF2394.avi --host=127.0.0.1 --port=7722
/tmp/xxxx/DSCF2394.avi sync success
手动检查文件正确性:
# md5sum /tmp/xxxx/DSCF2394.avi
eb50332d3b3b6f36b773046aca16e908  /tmp/xxxx/DSCF2394.avi
# md5sum /root/Videos/DSCF2394.avi
eb50332d3b3b6f36b773046aca16e908  /root/Videos/DSCF2394.avi
转:
阅读(2935) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~