Go语言 之TCP文件传输
<p><span style="font-size: 15px">服务端实现流程大致如下:</span></p><ol>
<li><span style="font-size: 15px">创建监听listener,程序结束时关闭。</span></li>
<li><span style="font-size: 15px">阻塞等待客户端连接,程序结束时关闭conn。</span></li>
<li><span style="font-size: 15px">读取客户端发送文件名。保存fileName。</span></li>
<li><span style="font-size: 15px">回发“ok”给客户端做应答</span></li>
<li><span style="font-size: 15px">封装函数 RecvFile接收客户端发送的文件内容。传参fileName 和conn</span></li>
<li><span style="font-size: 15px">按文件名Create文件,结束时Close</span></li>
<li><span style="font-size: 15px">循环Read客户端发送的文件内容,当读到EOF说明文件读取完毕。</span></li>
<li><span style="font-size: 15px">将读到的内容原封不动Write到创建的文件中</span></li>
</ol>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main
import (
</span>"fmt"
"net"
"os"
"runtime"<span style="color: rgba(0, 0, 0, 1)">
)
func Handler(conn net</span>.<span style="color: rgba(0, 0, 0, 1)">Conn) {
buf </span>:= make([]byte, 2048<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">读取客户端发送的内容</span>
n, err := conn.<span style="color: rgba(0, 0, 0, 1)">Read(buf)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
fmt</span>.<span style="color: rgba(0, 0, 0, 1)">Println(err)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
fileName </span>:= <span style="color: rgba(0, 0, 255, 1)">string</span>(buf[:<span style="color: rgba(0, 0, 0, 1)">n])
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取客户端ip+port</span>
addr := conn.RemoteAddr().<span style="color: rgba(0, 0, 255, 1)">String</span><span style="color: rgba(0, 0, 0, 1)">()
fmt</span>.Println(addr + ": 客户端传输的文件名为--" +<span style="color: rgba(0, 0, 0, 1)"> fileName)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">告诉客户端已经接收到文件名</span>
conn.Write([]byte("ok"<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建文件</span>
f, err := os.<span style="color: rgba(0, 0, 0, 1)">Create(fileName)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
fmt</span>.<span style="color: rgba(0, 0, 0, 1)">Println(err)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">循环接收客户端传递的文件内容</span>
<span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> {
buf </span>:= make([]byte, 2048<span style="color: rgba(0, 0, 0, 1)">)
n</span>, _ := conn.<span style="color: rgba(0, 0, 0, 1)">Read(buf)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">结束协程</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> <span style="color: rgba(0, 0, 255, 1)">string</span>(buf[:n]) == "finish"<span style="color: rgba(0, 0, 0, 1)"> {
fmt</span>.Println(addr + ": 协程结束"<span style="color: rgba(0, 0, 0, 1)">)
runtime</span>.<span style="color: rgba(0, 0, 0, 1)">Goexit()
}
f</span>.Write(buf[:<span style="color: rgba(0, 0, 0, 1)">n])
}
defer conn</span>.<span style="color: rgba(0, 0, 0, 1)">Close()
defer f</span>.<span style="color: rgba(0, 0, 0, 1)">Close()
}
func main() {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建tcp监听</span>
listen, err := net.Listen("tcp", ":8000"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
fmt</span>.<span style="color: rgba(0, 0, 0, 1)">Println(err)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
defer listen</span>.<span style="color: rgba(0, 0, 0, 1)">Close()
</span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">阻塞等待客户端</span>
conn, err := listen.<span style="color: rgba(0, 0, 0, 1)">Accept()
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
fmt</span>.<span style="color: rgba(0, 0, 0, 1)">Println(err)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建协程</span>
<span style="color: rgba(0, 0, 0, 1)"> go Handler(conn)
}
}</span></pre>
</div>
<p><span style="font-size: 15px">客户端实现流程大致如下:</span></p>
<ol>
<li><span style="font-size: 15px">提示用户输入文件名。接收文件名path(含访问路径)</span></li>
<li><span style="font-size: 15px">使用os.Stat()获取文件属性,得到纯文件名(去除访问路径)</span></li>
<li><span style="font-size: 15px">主动连接服务器,结束时关闭连接</span></li>
<li><span style="font-size: 15px">给接收端(服务器)发送文件名conn.Write()</span></li>
<li><span style="font-size: 15px">读取接收端回发的确认数据conn.Read()</span></li>
<li><span style="font-size: 15px">判断是否为“ok”。如果是,封装函数SendFile() 发送文件内容。传参path和conn</span></li>
<li><span style="font-size: 15px">只读Open文件, 结束时Close文件</span></li>
<li><span style="font-size: 15px">循环读文件,读到EOF终止文件读取</span></li>
<li><span style="font-size: 15px">将读到的内容原封不动Write给接收端(服务器)</span></li>
</ol>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">package main
import (
</span>"fmt"
"io"
"net"
"os"<span style="color: rgba(0, 0, 0, 1)">
)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">发送文件到服务端</span>
func SendFile(filePath <span style="color: rgba(0, 0, 255, 1)">string</span>, <span style="color: rgba(0, 128, 128, 1)">fileSize</span> int64, conn net.<span style="color: rgba(0, 0, 0, 1)">Conn) {
f</span>, err := os.<span style="color: rgba(0, 0, 0, 1)">Open(filePath)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
fmt</span>.<span style="color: rgba(0, 0, 0, 1)">Println(err)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
defer f</span>.<span style="color: rgba(0, 0, 0, 1)">Close()
</span><span style="color: rgba(0, 0, 255, 1)">var</span> <span style="color: rgba(0, 128, 128, 1)">count</span><span style="color: rgba(0, 0, 0, 1)"> int64
</span><span style="color: rgba(0, 0, 255, 1)">for</span><span style="color: rgba(0, 0, 0, 1)"> {
buf </span>:= make([]byte, 2048<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">读取文件内容</span>
n, err := f.<span style="color: rgba(0, 0, 0, 1)">Read(buf)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err != nil && io.EOF ==<span style="color: rgba(0, 0, 0, 1)"> err {
fmt</span>.Println("文件传输完成"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">告诉服务端结束文件接收</span>
conn.Write([]byte("finish"<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">发送给服务端</span>
conn.Write(buf[:<span style="color: rgba(0, 0, 0, 1)">n])
</span><span style="color: rgba(0, 128, 128, 1)">count</span> +=<span style="color: rgba(0, 0, 0, 1)"> int64(n)
sendPercent </span>:= float64(<span style="color: rgba(0, 128, 128, 1)">count</span>) / float64(<span style="color: rgba(0, 128, 128, 1)">fileSize</span>) * 100<span style="color: rgba(0, 0, 0, 1)">
value </span>:= fmt.<span style="color: rgba(0, 128, 128, 1)">Sprintf</span>("%.2f",<span style="color: rgba(0, 0, 0, 1)"> sendPercent)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">打印上传进度</span>
fmt.Println("文件上传:" + value + "%"<span style="color: rgba(0, 0, 0, 1)">)
}
}
func main() {
fmt</span>.<span style="color: rgba(0, 0, 255, 1)">Print</span>("请输入文件的完整路径:"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建切片,用于存储输入的路径</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> str <span style="color: rgba(0, 0, 255, 1)">string</span><span style="color: rgba(0, 0, 0, 1)">
fmt</span>.Scan(&<span style="color: rgba(0, 0, 0, 1)">str)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取文件信息</span>
fileInfo, err := os.<span style="color: rgba(0, 128, 128, 1)">Stat</span><span style="color: rgba(0, 0, 0, 1)">(str)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
fmt</span>.<span style="color: rgba(0, 0, 0, 1)">Println(err)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建客户端连接</span>
conn, err := net.Dial("tcp", ":8000"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
fmt</span>.<span style="color: rgba(0, 0, 0, 1)">Println(err)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
defer conn</span>.<span style="color: rgba(0, 0, 0, 1)">Close()
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">文件名称</span>
fileName := fileInfo.<span style="color: rgba(0, 0, 0, 1)">Name()
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">文件大小</span>
<span style="color: rgba(0, 128, 128, 1)">fileSize</span> := fileInfo.<span style="color: rgba(0, 0, 0, 1)">Size()
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">发送文件名称到服务端</span>
conn.<span style="color: rgba(0, 0, 0, 1)">Write([]byte(fileName))
buf </span>:= make([]byte, 2048<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">读取服务端内容</span>
n, err := conn.<span style="color: rgba(0, 0, 0, 1)">Read(buf)
</span><span style="color: rgba(0, 0, 255, 1)">if</span> err !=<span style="color: rgba(0, 0, 0, 1)"> nil {
fmt</span>.<span style="color: rgba(0, 0, 0, 1)">Println(err)
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)">
}
revData </span>:= <span style="color: rgba(0, 0, 255, 1)">string</span>(buf[:<span style="color: rgba(0, 0, 0, 1)">n])
</span><span style="color: rgba(0, 0, 255, 1)">if</span> revData == "ok"<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">发送文件数据</span>
SendFile(str, <span style="color: rgba(0, 128, 128, 1)">fileSize</span>,<span style="color: rgba(0, 0, 0, 1)"> conn)
}
}</span></pre>
</div>
<p> </p><br><br>
来源:https://www.cnblogs.com/yang-2018/p/11147418.html
頁:
[1]