//多协程文件传输服务端
//作者:LvanNeo
//邮箱:lvan_software@foxmail.com
//版本:1.0
//日期:2013-09-26
//对每个请求由一个单独的协程进行处理,文件接收完成后由一个协负责将所有接收的数据合并成一个有效文件
package main
import (
"bytes"
"fmt"
"net"
"os"
"runtime"
"strconv"
)
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
func main() {
var (
// host = "192.168.1.5" //如果写locahost或127.0.0.1则只能本地访问。
port = "9090"
// remote = host + ":" + port
remote = ":" + port //此方式本地与非本地都可访问
)
fmt.Println("服务器初始化... (Ctrl-C 停止)")
lis, err := net.Listen("tcp", remote)
defer lis.Close()
if err != nil {
fmt.Println("监听端口发生错误: ", remote)
os.Exit(-1)
}
for {
conn, err := lis.Accept()
if err != nil {
fmt.Println("客户端连接错误: ", err.Error())
// os.Exit(0)
continue
}
//调用文件接收方法
go receiveFile(conn)
}
}
/*
* 文件接收方法
* 2013-09-26
* LvanNeo
*
* con 连接成功的客户端连接
*/
func receiveFile(con net.Conn) {
var (
res string
tempFileName string //保存临时文件名称
data = make([]byte, 1024*1024) //用于保存接收的数据的切片
by []byte
databuf = bytes.NewBuffer(by) //数据缓冲变量
fileNum int //当前协程接收的数据在原文件中的位置
)
defer con.Close()
fmt.Println("新建立连接: ", con.RemoteAddr())
j := 0 //标记接收数据的次数
for {
length, err := con.Read(data)
if err != nil {
// writeend(tempFileName, databuf.Bytes())
da := databuf.Bytes()
// fmt.Println("over", fileNum, len(da))
fmt.Printf("客户端 %v 已断开. %2d %d \n", con.RemoteAddr(), fileNum, len(da))
return
}
if 0 == j {
res = string(data[0:8])
if "fileover" == res { //判断是否为发送结束指令,且结束指令会在第一次接收的数据中
xienum := int(data[8])
mergeFileName := string(data[9:length])
go mainMergeFile(xienum, mergeFileName) //合并临时文件,生成有效文件
res = "文件接收完成: " + mergeFileName
con.Write([]byte(res))
fmt.Println(mergeFileName, "文件接收完成")
return
} else { //创建临时文件
fileNum = int(data[0])
tempFileName = string(data[1:length]) + strconv.Itoa(fileNum)
fmt.Println("创建临时文件:", tempFileName)
fout, err := os.Create(tempFileName)
if err != nil {
fmt.Println("创建临时文件错误", tempFileName)
return
}
fout.Close()
}
} else {
// databuf.Write(data[0:length])
writeTempFileEnd(tempFileName, data[0:length])
}
res = strconv.Itoa(fileNum) + " 接收完成"
con.Write([]byte(res))
j++
}
}
/*
* 把数据写入指定的临时文件中
* 2013-09-26
* LvanNeo
*
* fileName 临时文件名
* data 接收的数据
*/
func writeTempFileEnd(fileName string, data []byte) {
// fmt.Println("追加:", name)
tempFile, err := os.OpenFile(fileName, os.O_APPEND|os.O_RDWR, 0666)
if err != nil {
// panic(err)
fmt.Println("打开临时文件错误", err)
return
}
defer tempFile.Close()
tempFile.Write(data)
}
/*
* 根据临时文件数量及有效文件名称生成文件合并规则进行文件合并
* 2013-09-26
* LvanNeo
*
* connumber 临时文件数量
* filename 有效文件名称
*/
func mainMergeFile(connumber int, filename string) {
file, err := os.Create(filename)
if err != nil {
fmt.Println("创建有效文件错误", err)
return
}
defer file.Close()
//依次对临时文件进行合并
for i := 0; i < connumber; i++ {
mergeFile(filename+strconv.Itoa(i), file)
}
//删除生成的临时文件
for i := 0; i < connumber; i++ {
os.Remove(filename + strconv.Itoa(i))
}
}
/*
* 将指定临时文件合并到有效文件中
* 2013-09-26
* LvanNeo
*
* rfilename 临时文件名称
* wfile 有效文件
*/
func mergeFile(rfilename string, wfile *os.File) {
// fmt.Println(rfilename, wfilename)
rfile, err := os.OpenFile(rfilename, os.O_RDWR, 0666)
defer rfile.Close()
if err != nil {
fmt.Println("合并时打开临时文件错误:", rfilename)
return
}
stat, err := rfile.Stat()
if err != nil {
panic(err)
}
num := stat.Size()
buf := make([]byte, 1024*1024)
for i := 0; int64(i) < num; {
length, err := rfile.Read(buf)
if err != nil {
fmt.Println("读取文件错误")
}
i += length
wfile.Write(buf[:length])
}
}
//多协程文件传输客户端
//作者:LvanNeo
//邮箱:lvan_software@foxmail.com
//版本:1.0
//日期:2013-09-26
//对待发送文件进行拆分,由多个协程异步进行发送
package main
import (
"bufio"
"bytes"
"fmt"
"net"
"os"
"runtime"
"strconv"
"time"
)
func init() {
runtime.GOMAXPROCS(runtime.NumCPU())
}
func main() {
var (
host = "192.168.1.8" //服务端IP
port = "9090" //服务端端口
remote = host + ":" + port //构造连接串
fileName = "node.exe" //待发送文件名称
mergeFileName = "mm.exe" //待合并文件名称
coroutine = 10 //协程数量或拆分文件的数量
bufsize = 1024 //单次发送数据的大小
)
//获取参数信息。
//参数顺序:
// 1:待发送文件名
// 2:待合并文件名
// 3:单次发送数据大小
// 4:协程数量或拆分文件数量
for index, sargs := range os.Args {
switch index {
case 1:
fileName = sargs
mergeFileName = sargs
case 2:
mergeFileName = sargs
case 3:
bufsize, _ = strconv.Atoi(sargs)
case 4:
coroutine, _ = strconv.Atoi(sargs)
}
}
fmt.Printf("请输入服务端IP: ")
reader := bufio.NewReader(os.Stdin)
ipdata, _, _ := reader.ReadLine()
host = string(ipdata)
remote = host + ":" + port
fl, err := os.OpenFile(fileName, os.O_RDWR, 0666)
if err != nil {
fmt.Println("userFile", err)
return
}
stat, err := fl.Stat() //获取文件状态
if err != nil {
panic(err)
}
var size int64
size = stat.Size()
fl.Close()
littleSize := size / int64(coroutine)
fmt.Printf("Size: %d %d \n", size, littleSize)
begintime := time.Now().Unix()
//对待发送文件进行拆分计算并调用发送方法
c := make(chan string)
var begin int64 = 0
for i := 0; i < coroutine; i++ {
if i == coroutine-1 {
go splitFile(remote, c, i, bufsize, fileName, mergeFileName, begin, size)
fmt.Println(begin, size, bufsize)
} else {
go splitFile(remote, c, i, bufsize, fileName, mergeFileName, begin, begin+littleSize)
fmt.Println(begin, begin+littleSize)
}
begin += littleSize
}
//同步等待发送文件的协程
for j := 0; j < coroutine; j++ {
fmt.Println(<-c)
}
midtime := time.Now().Unix()
sendtime := midtime - begintime
fmt.Printf("发送耗时:%d 分 %d 秒 \n", sendtime/60, sendtime%60)
sendMergeCommand(remote, mergeFileName, coroutine) //发送文件合并指令及文件名
endtime := time.Now().Unix()
mergetime := endtime - midtime
fmt.Printf("合并耗时:%d 分 %d 秒 \n", mergetime/60, mergetime%60)
tot := endtime - begintime
fmt.Printf("总计耗时:%d 分 %d 秒 \n", tot/60, tot%60)
}
/*
* 文件拆分发送方法
* 2013-09-26
* LvanNeo
*
* remote 服务端IP及端口号(如:192.168.1.8:9090)
* c channel,用于同步协程
* coroutineNum 协程顺序或拆分文件的顺序
* size 发送数据的大小
* fileName 待发送的文件名
* mergeFileName 待合并的文件名
* begin 当前协程拆分待发送文件中的开始位置
* end 当前协程拆分待发送文件中的结束位置
*/
func splitFile(remote string, c chan string, coroutineNum int, size int, fileName, mergeFileName string, begin int64, end int64) {
con, err := net.Dial("tcp", remote)
defer con.Close()
if err != nil {
fmt.Println("服务器连接失败.")
os.Exit(-1)
return
}
fmt.Println(coroutineNum, "连接已建立.文件发送中...")
var by [1]byte
by[0] = byte(coroutineNum)
var bys []byte
databuf := bytes.NewBuffer(bys) //数据缓冲变量
databuf.Write(by[:])
databuf.WriteString(mergeFileName)
bb := databuf.Bytes()
// bb := by[:]
// fmt.Println(bb)
in, err := con.Write(bb) //向服务器发送当前协程的顺序,代表拆分文件的顺序
if err != nil {
fmt.Printf("向服务器发送数据错误: %d\n", in)
os.Exit(0)
}
var msg = make([]byte, 1024) //创建读取服务端信息的切片
lengthh, err := con.Read(msg) //确认服务器已收到顺序数据
if err != nil {
fmt.Printf("读取服务器数据错误.\n", lengthh)
os.Exit(0)
}
// str := string(msg[0:lengthh])
// fmt.Println("服务端信息:",str)
//打开待发送文件,准备发送文件数据
file, err := os.OpenFile(fileName, os.O_RDWR, 0666)
defer file.Close()
if err != nil {
fmt.Println(fileName, "-文件打开错误.")
os.Exit(0)
}
file.Seek(begin, 0) //设定读取文件的位置
buf := make([]byte, size) //创建用于保存读取文件数据的切片
var sendDtaTolNum int = 0 //记录发送成功的数据量(Byte)
//读取并发送数据
for i := begin; int64(i) < end; i += int64(size) {
length, err := file.Read(buf) //读取数据到切片中
if err != nil {
fmt.Println("读文件错误", i, coroutineNum, end)
}
//判断读取的数据长度与切片的长度是否相等,如果不相等,表明文件读取已到末尾
if length == size {
//判断此次读取的数据是否在当前协程读取的数据范围内,如果超出,则去除多余数据,否则全部发送
if int64(i)+int64(size) >= end {
sendDataNum, err := con.Write(buf[:size-int((int64(i)+int64(size)-end))])
if err != nil {
fmt.Printf("向服务器发送数据错误: %d\n", sendDataNum)
os.Exit(0)
}
sendDtaTolNum += sendDataNum
} else {
sendDataNum, err := con.Write(buf)
if err != nil {
fmt.Printf("向服务器发送数据错误: %d\n", sendDataNum)
os.Exit(0)
}
sendDtaTolNum += sendDataNum
}
} else {
sendDataNum, err := con.Write(buf[:length])
if err != nil {
fmt.Printf("向服务器发送数据错误: %d\n", sendDataNum)
os.Exit(0)
}
sendDtaTolNum += sendDataNum
}
//读取服务器端信息,确认服务端已接收数据
lengths, err := con.Read(msg)
if err != nil {
fmt.Printf("读取服务器数据错误.\n", lengths)
os.Exit(0)
}
// str := string(msg[0:lengths])
// fmt.Println("服务端信息:",str)
}
fmt.Println(coroutineNum, "发送数据(Byte):", sendDtaTolNum)
c <- strconv.Itoa(coroutineNum) + " 协程退出"
}
/*
* 向服务端发送待合并文件的名称及合并指令
* 2013-09-26
* LvanNeo
*
* remote 服务端IP及端口号(如:192.168.1.8:9090)
* mergeFileName 待合并的文件名
* coroutine 拆分文件的总个数
*/
func sendMergeCommand(remote, mergeFileName string, coroutine int) {
con, err := net.Dial("tcp", remote)
defer con.Close()
if err != nil {
fmt.Println("服务器连接失败.")
os.Exit(-1)
return
}
fmt.Println("连接已建立. 发送合并指令.\n文件合并中...")
var by [1]byte
by[0] = byte(coroutine)
var bys []byte
databuf := bytes.NewBuffer(bys) //数据缓冲变量
databuf.WriteString("fileover")
databuf.Write(by[:])
databuf.WriteString(mergeFileName)
cmm := databuf.Bytes()
in, err := con.Write(cmm)
if err != nil {
fmt.Printf("向服务器发送数据错误: %d\n", in)
}
var msg = make([]byte, 1024)
lengthh, err := con.Read(msg)
if err != nil {
fmt.Printf("读取服务器数据错误.\n", lengthh)
os.Exit(0)
}
str := string(msg[0:lengthh])
fmt.Println("传输完成(服务端信息): ", str)
}
相关推荐
SPARTAN6 + Verilog - FPGA step by step 从0开始学习(1)
SPARTAN6 + Verilog - FPGA step by step 从0开始学习(1)Step 1 软件安装Step 2 硬件获取Step 3 开始从头到脚建一个工程Step 3.1 新建一个工程 从0开始学习FPGA,最好的办法就是先建一个最简单的模块,并且跑起来,然后再慢慢展开。下面这个例子是要按照一定的周期点亮核心板上的一个led。 Step 1 软件安装 这个从0开始学习是用的xilinx的SPARTAN6。SPARTAN6集成开发环境用ISE,不能用Vivado,各自对应的版本不同。安装
go轻量级分布式与微服务
本节为go轻量级分布式与微服务,主要讲解go语言在轻量级分布式与微服务方面的一些应用,包括爬虫、多线程设计模式、mapreduce等。
TensorRT-LLM环境配置避坑指南:从安装到实战
本文是一份详尽的TensorRT-LLM环境配置避坑指南。文章重点解析了从Python、CUDA、PyTorch版本选择,到解决mpi4py安装这一核心难题的完整流程,并提供了经过验证的稳定版本组合与实战排错方案,帮助开发者高效部署大语言模型推理优化环境。
golang文件上传到服务器,golang文件传输服务
续上篇,本篇介绍一个完整的golang文件传输服务器。完整的代码可以看服务器,客户端网络使用的框架如上篇介绍,这里就不再复述.首先定义3个命令码:const (request_file= 1file_size= 2transfering= 3)request_file用于请求文件传输,附带的命令参数是文件key.file_size用于通告客户端文件的大小.transfering用于传输文件内容,附...
万达电影 com.wandafilm.app headers check
万达电影 安卓逆向 抓包 逆向 check
ESP32连接PDM麦克风操作指南:新手入门必看
手把手教你如何将ESP32与PDM麦克风连接,采集音频数据并用于音频分类应用。内容涵盖硬件接线、代码配置及实际调试技巧,适合初学者快速上手esp32在声音识别场景中的使用。
golang gin——文件上传(单文件,多文件)
从form-data获取文件。
Cocos Creator发布微信小游戏:深度定制与去除默认加载页面的实践指南
本文详细介绍了如何使用Cocos Creator发布微信小游戏时去除默认加载页面的实践方法。通过修改构建配置和重写启动逻辑,开发者可以自定义加载体验,提升品牌一致性。文章还提供了进阶优化方案和常见问题解决方案,帮助开发者实现更专业的微信小游戏发布流程。
golang 下载和上传,处理多文件上传
package main import ( "net/http" "os" "io" "strconv") func main() { f, err := os.OpenFile("K:/file.mp3", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666) stat, err := f.Stat() //获取文件状...
问题解答:如何不通过修改底层数据库表的方式,给数据库对应的数据结构,增添新的字段?
现在需要将这张表里的内容读取到 ABAP 内表里,并且针对每个行项目,增加一个新的列字段,我随便举个例子,这个列字段名称叫 LENGTH,值为 OBJ_NAME 字段的长度,使用。最笨的办法就是下面这样定义一个新的类型,这个类型的每个字段名称,都来自数据库表 TADIR 的同名字段,在末尾再增添自定义字段 length.其实我们是做 ALV 输出,只需要 ABAP 内表变量的类型,包含 TADIR 数据库表的全部字段,再加上新的 LENGTH 字段即可。这相当于多了一个中间层,没办法直接被 ALV 处理。
ImportError: DLL load failed while importing _pydantic_core: 找不到指定的程序对应解决方案
本文主要介绍了ImportError: DLL load failed while importing _pydantic_core: 找不到指定的程序对应解决方案,希望能对使用Python的同学们有所帮助。 文章目录 1. 问题描述 2. 解决方案
【指南】怎样轻松愉悦地在服务器上用百度网盘进行文件传输
面对冷冰冰的 Linux 服务器终端,想传几个大文件(比如数据集、模型权重)到百度网盘,还在用本地电脑下载再龟速上传到服务器?今天我们用两款开源工具,高性能的和 简洁亲民的,让文件传输变得像德芙一样流畅。
MC_SetOverride指令详细应用介绍(基恩士PLC)
基恩士KV系列PLC和松下总线绝对值伺服运动控制(详细配置+轴控完整ST源代码)
告别传统FTP:现代文件传输工具的效率革命
传统FTP单线程传输就像单车道高速公路,而现代工具采用多线程分块技术,相当于同时开通多条车道。如果你也受够了缓慢的传输体验,不妨试试自己动手开发,或者直接用现成方案升级工作流程。最近在项目中需要频繁传输大文件,传统FTP工具的速度和稳定性让我头疼不已。经过几周的摸索和实践,总结出一些提升文件传输效率的关键技术点,分享给大家。比如从办公室电脑传到家里NAS时,会先压缩上传到云端中转,家里设备再从云端下载,比直连更稳定。新工具会实时记录每个分块的传输状态,意外中断后可以从断点继续,不再需要从头开始。
jdk-8u144-linux-x64.tar.gz.
该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包
jre9下载 jdk9
(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】
vLLM NixlConnector 兼容性矩阵详解:PD 分离场景下的模型架构与功能支持边界
NixlConnector 是 vLLM 在分离式预填充(Disaggregated Prefilling)场景下,基于 NIXL 库实现高性能 KV Cache 传输的连接器。不同模型架构(Dense Transformer、MLA、Mamba、MoE、多模态等)在搭配各类高级特性(投机解码、异构张量并行、滑动窗口注意力、跨层共享 KV block 等)时,其能力边界并不相同。本文以官方兼容性矩
Devexpress16.2.6破解工具
Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具
最新的go 上传ftp脚本2-3分钟上传1万多文件
package main import ( "io" "os" "fmt" "net" "sync" "path" "time" // "math" "errors" "bytes" "os/exec"
最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版
Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。
BaiduPCS-Go网络请求分析:API调用流程与数据交互
在使用BaiduPCS-Go进行文件上传下载时,你是否好奇背后的网络请求是如何实现的?本文将深入剖析BaiduPCS-Go的网络请求模块,带你了解从API调用到数据交互的完整流程。读完本文,你将掌握网络请求的配置细节、下载上传的实现机制以及错误处理策略。 ## 网络请求核心组件 BaiduPCS-Go的网络请求功能主要由`requester`包实现,该包提供了HTTP客户端配置、请求发送和响应...
突破百度网盘文件管理瓶颈:BaiduPCS-Go架构解析与自动化最佳实践
面对百度网盘官方客户端功能限制和操作繁琐的痛点,BaiduPCS-Go作为基于Go语言开发的命令行工具,为技术用户提供了高效管理百度网盘文件的终极解决方案。这款开源项目在原版基础上集成了分享链接和秒传链接转存功能,通过命令行界面实现了类Linux的文件操作体验,显著提升了文件管理的自动化水平和效率。 ## 解决登录认证难题:多账户管理与安全配置 传统百度网盘客户端在多账户切换和认证管理上存在诸
OpenMTP:macOS与Android文件传输的终极免费解决方案
还在为macOS和Android设备之间的文件传输问题而烦恼吗?每次想要传输照片、视频或文档时,都要面对连接不稳定、传输速度慢、大文件无法传输的困扰?OpenMTP正是为你量身打造的开源解决方案!这款macOS平台上的Android文件传输应用,不仅完全免费,还提供了前所未有的传输体验。OpenMTP通过创新的Kalam内核技术,彻底解决了传统MTP传输工具的种种限制,让macOS用户能够轻松、快
服务器文件传输优化:百度网盘集成方案详解
文件传输是服务器运维中的基础需求,传统SCP/SFTP协议存在带宽限制和缺乏可视化管理的痛点。通过云存储技术集成可实现断点续传和加速传输,其中百度网盘凭借其成熟的客户端技术成为优选方案。BaiduPCS-Go和bypy两种工具分别提供命令行和编程接口的集成方式,支持多线程加速和自动化脚本对接。在持续集成场景中,结合crontab定时任务或GitLab Runner可实现日志备份、制品发布等自动化流程。针对大文件传输场景,合理配置并发线程数和断点续传参数可显著提升传输效率,实测显示多线程可将传输速度提升3倍以
OpenMTP技术架构深度解析:macOS平台上高性能Android文件传输的实现机制
在macOS生态中,Android设备文件传输一直是一个技术痛点,传统解决方案受限于MTP协议实现效率低下、大文件传输限制等问题。OpenMTP作为一款开源的高性能Android文件传输工具,通过创新的技术架构解决了这些难题。本文将深入分析OpenMTP的技术实现原理、架构设计以及性能优化策略,为开发者提供跨平台文件传输系统的技术参考。 ## MTP协议的技术挑战与OpenMTP的解决方案 媒
SCP-GO——兼容SCP命令的多线程实现
SCP(Secure Copy Protocol)是一种基于SSH协议的安全文件传输命令,用于在本地和远程服务器之间复制文件和目录。它是系统管理员、开发人员和DevOps工程师日常工作中不可或缺的工具,广泛应用于代码部署、配置文件同步、数据备份等场景。其中,source和target可以是本地路径或远程路径(格式为SCP-Go是一个用Go语言实现的SCP命令替代品,旨在解决现有SCP命令的性能瓶颈和用户体验问题。✅多线程文件传输:利用现代多核CPU,显著提高传输速度✅实时进度显示。
如何用OpenMTP解决macOS与Android文件传输难题:完整指南
还在为macOS和Android设备之间的文件传输问题而烦恼吗?你是否曾经尝试过官方Android File Transfer,却频繁遇到连接断开、大文件无法传输、界面简陋的问题?OpenMTP正是为解决这些痛点而生的开源解决方案!这款macOS平台上的Android文件传输应用,不仅完全免费,还提供了前所未有的传输体验。通过创新的Kalam内核技术,OpenMTP彻底解决了传统MTP传输工具的种
BaiduPCS-Go双令牌认证机制深度解析与架构设计
BaiduPCS-Go作为百度网盘的高效命令行客户端,其核心技术在于对百度网盘API的深度集成和优化。本文将从技术架构、认证机制、文件传输优化三个维度,深度解析BaiduPCS-Go的设计理念与实现细节,为开发者提供架构参考和最佳实践指导。核心关键词包括:百度网盘API集成、双令牌认证系统、STOKEN-BDUSS机制、多线程下载优化、命令行云存储管理。 ## 技术架构设计解析 BaiduPC
golang实现文件传输
服务段代码: package main import ( "bytes" "fmt" "io/ioutil" "net" "os" "os/exec" "runtime" "strconv" "strings" "syscall" ) func initEnv(i ...int) { c:=1 if len(i) == 0 { if runtime.GOOS==...
如何高效管理百度网盘:5大优势的BaiduPCS-Go命令行工具完整指南
BaiduPCS-Go是一款强大的百度网盘命令行客户端,它通过仿Linux shell的操作方式,让技术爱好者和开发者能够高效管理网盘资源。这个开源工具不仅支持Windows、macOS和Linux全平台,还提供了批量操作、断点续传、脚本自动化等高级功能,彻底改变了传统网页界面操作繁琐、速度缓慢的痛点。 ## 🚀 为什么选择命令行工具管理百度网盘? 传统的百度网盘操作往往需要频繁点击鼠标、等
5507



被折叠的 条评论
为什么被折叠?



