@H_
404_0@在日常编程中,我们肯定会遇到用socket传送
文件内容,如果是大
文件的,总不能传送到一半因某原因断掉了,又从新传送
文件内容吧。对,我们需要续传,也就是接着上次传送的位置继续发送
文件内容。
@H_
404_0@续传的话,其实并不难,我理解的思路大概如下:
- 客户端发送消息询问服务端,你上次接收到的文件内容位置
- 服务端告诉客户端上次接收到的文件内容位置
- 客户端就从上次断点的位置继续发送文件内容
- 客户端发送文件内容完毕后通知服务端,然后断开连接
@H_
404_0@下面我们看看
代码的实现
服务端
package main
import (
"os"
"io"
"net"
"log"
"strconv"
)
func writeFile(content []byte) {
if len(content) != 0 {
fp,err := os.OpenFile("test_1.txt",os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0755)
defer fp.Close()
if err != nil {
log.Fatalf("open file faild: %s\n",err)
}
_,err = fp.Write(content)
if err != nil {
log.Fatalf("append content to file faild: %s\n",err)
}
log.Printf("append content: 【%s】 success\n",string(content))
}
}
func getFileStat() int64 {
fileinfo,err := os.Stat("test_1.txt")
if err != nil {
if os.IsNotExist(err) {
log.Printf("file size: %d\n", 0)
return int64(0)
}
log.Fatalf("get file stat faild: %s\n",err)
}
log.Printf("file size: %d\n",fileinfo.Size())
return fileinfo.Size()
}
func serverConn(conn net.Conn) {
defer conn.Close()
for {
var buf = make([]byte, 10)
n,err := conn.Read(buf)
if err != nil {
if err == io.EOF {
log.Println("server io EOF\n")
return
}
log.Fatalf("server read faild: %s\n",err)
}
log.Printf("recevice %d bytes,content is 【%s】\n",n,string(buf[:n]))
switch string(buf[:n]) {
case "start-->":
off := getFileStat()
stringoff := strconv.FormatInt(off, 10)
_,err = conn.Write([]byte(stringoff))
if err != nil {
log.Fatalf("server write faild: %s\n",err)
}
continue
case "<--end":
log.Fatalf("receive over\n")
return
}
writeFile(buf[:n])
}
}
func main() {
l,err := net.Listen("tcp",":8888")
if err != nil {
log.Fatalf("error listen: %s\n",err)
}
defer l.Close()
log.Println("waiting accept.")
conn,err := l.Accept()
if err != nil {
log.Fatalf("accept faild: %s\n",err)
}
serverConn(conn)
}
客户端
package main
import (
"os"
"io"
"net"
"log"
"time"
"strconv"
)
func clientRead(conn net.Conn) int {
buf := make([]byte, 5)
n,err := conn.Read(buf)
if err != nil {
log.Fatalf("receive server info faild: %s\n",err)
}
off,err := strconv.Atoi(string(buf[:n]))
if err != nil {
log.Fatalf("string conver int faild: %s\n",err)
}
return off
}
func clientWrite(conn net.Conn,data []byte) {
_,err := conn.Write(data)
if err != nil {
log.Fatalf("send 【%s】 content faild: %s\n",string(data),err)
}
log.Printf("send 【%s】 content success\n",string(data))
}
func clientConn(conn net.Conn) {
defer conn.Close()
clientWrite(conn,[]byte("start-->"))
off := clientRead(conn)
fp,err := os.OpenFile("test.txt",os.O_RDONLY, 0755)
if err != nil {
log.Fatalf("open file faild: %s\n",err)
}
defer fp.Close()
_,err = fp.Seek(int64(off), 0)
if err != nil {
log.Fatalf("set file seek faild: %s\n",err)
}
log.Printf("read file at seek: %d\n",off)
for {
data := make([]byte,err := fp.Read(data)
if err != nil {
if err == io.EOF {
time.Sleep(time.Second * 1)
clientWrite(conn,[]byte("<--end"))
log.Println("send all content,now quit")
break
}
log.Fatalf("read file err: %s\n",err)
}
clientWrite(conn,data[:n])
}
}
func main() {
conn,err := net.DialTimeout("tcp",":8888",time.Second * 10)
if err != nil {
log.Fatalf("client dial faild: %s\n",err)
}
clientConn(conn)
}
@H_
404_0@客户端读取
文件test.txt
内容发送到服务端,服务端把接收到的
文件内容保存在
test_1.txt
文件中。我们模拟断点续传的方式是:
- 第一次先发送
test.txt
文件内容到服务端
- 修改
test.txt
文件,加一些内容
- 再次运行server socket以及client socket,观察客户端是不是只发送新增的文件内容到服务端
$ cat test.txt
hello golang.
$ go run server.go
$ go run client.go
2018/04/05 23:37:13 waiting accept.
2018/04/05 23:37:15 recevice 8 bytes,content is 【start
2018/04/05 23:37:15 file size: 0
2018/04/05 23:37:15 recevice 10 bytes,content is 【hello gola】
2018/04/05 23:37:15 append content: 【hello gola】 success
2018/04/05 23:37:15 recevice 2 bytes,content is 【n.】
2018/04/05 23:37:15 append content: 【n.】 success
2018/04/05 23:37:16 recevice 6 bytes,content is 【<
2018/04/05 23:37:16 receive over
exit status 1
2018/04/05 23:37:15 send 【start
2018/04/05 23:37:15 read file at seek: 0
2018/04/05 23:37:15 send 【hello gola】 content success
2018/04/05 23:37:15 send 【n.】 content success
2018/04/05 23:37:16 send 【<
2018/04/05 23:37:16 send all content,now quit
$ cat test_1.txt
hello golan.
$ cat test.txt
hello golang.
hello python.
$ go run server.go
$ go run client.go
2018/04/05 23:44:31 waiting accept.
2018/04/05 23:44:34 recevice 8 bytes,content is 【start
2018/04/05 23:44:34 file size: 12
2018/04/05 23:44:34 recevice 10 bytes,content is 【
hello pyt】
2018/04/05 23:44:34 append content: 【
hello pyt】 success
2018/04/05 23:44:34 recevice 4 bytes,content is 【hon.】
2018/04/05 23:44:34 append content: 【hon.】 success
2018/04/05 23:44:35 recevice 6 bytes,content is 【<
2018/04/05 23:44:35 receive over
exit status 1
2018/04/05 23:44:34 send 【start
2018/04/05 23:44:34 read file at seek: 12
2018/04/05 23:44:34 send 【
hello pyt】 content success
2018/04/05 23:44:34 send 【hon.】 content success
2018/04/05 23:44:35 send 【<
2018/04/05 23:44:35 send all content,now quit
$ cat test_1.txt
hello golang.
hello python.
@H_
404_0@
好了,希望大家有个愉快的假期 ~~