TCP
よりもファイル転送に問題があります。go
です。ファイル転送は時には動作し、途中で止まってしまうことがあります。立ち往生すると、通信チャネル内のデータを期待しているように見えますが、データはなく、エラーもありません。したがって、無期限にスタックされます。事を混乱させるために、同じファイル、つまり同じファイルに対してこの動作を示します。時々動作しますが、動作しないことがあります。Golang TCPファイル転送が途中で止まってしまう
これは私のプログラムの仕組みです。着信要求を待ち受けます。リクエストはJSON
形式です。要求タイプに基づいて、別の操作を行います。私はファイル転送に関連するコードセグメントを投稿しています。
server.go
package main
import (
"bufio"
"encoding/json"
"fmt"
_"io"
"net"
"os"
)
const (
COMMAND_RECEIVE_FILE = "TRANSFER_FILE"
COMMAND_EXIT = "EXIT"
CONNECTION_TYPE = "tcp"
CONNECTION_PORT = "3645"
CONNECTION_HOST = ""
BUFFER_SIZE = 1024
)
type Command struct {
Identifier string `json:"identifier"`
Name string `json:"name"`
Size int64 `json:"size"`
}
type Result struct {
Message string `json:"message"`
}
func receiveFile(connection net.Conn, fileName string, fileSize int64) Result {
fmt.Println("Receiving file")
result := Result{Message: ""}
file, err := os.Create(fileName)
if err != nil {
fmt.Println(err)
result.Message = "Error opening file: " + fileName
return result
}
defer file.Close()
fileBuffer := make([]byte, BUFFER_SIZE)
bytesRead := int64(0)
count := 0
for {
if fileSize-bytesRead < int64(BUFFER_SIZE) {
fileBuffer = make([]byte, fileSize-bytesRead)
}
fmt.Println("Reading ", BUFFER_SIZE, " bytes of data")
n, err := connection.Read(fileBuffer)
count++
fmt.Println("Completed reading", n, " bytes of data, count=", count)
file.Write(fileBuffer[0:n])
bytesRead += int64(n)
if err != nil {
result.Message = "File transfer incomplete"
break
}
if bytesRead >= fileSize {
result.Message = "File transfer complete"
break
}
}
file.Chmod(0777)
return result
}
func main() {
ln, err := net.Listen(CONNECTION_TYPE, CONNECTION_HOST + ":"+CONNECTION_PORT)
if err != nil {
fmt.Println("error opening a tcp connection")
}
for {
fmt.Println("waiting for new connection")
conn, err := ln.Accept()
if err != nil {
} else {
var commandStr string
reader := bufio.NewReader(conn)
var exitStatus = 1
for exitStatus == 1 {
fmt.Println("Waiting for new command: ")
line,_,err := reader.ReadLine()
if err != nil {
conn.Close()
exitStatus = 0
break
} else {
fmt.Println("Size read :", len(line))
}
commandStr = string(line)
fmt.Println("CommandStr: ", commandStr)
var msg Command
err = json.Unmarshal([]byte(commandStr), &msg)
if err != nil {
fmt.Println("Error")
conn.Close()
break
}
result := Result{}
fmt.Println("Received new command: ", msg.Identifier)
switch msg.Identifier {
case COMMAND_RECEIVE_FILE:
result = receiveFile(conn, msg.Name, msg.Size)
case COMMAND_EXIT:
exitStatus = 0
conn.Close()
default:
result = Result{Message: "Unrecognized command"}
}
out, _ := json.Marshal(result)
fmt.Fprint(conn, string(out)+"\n")
}
}
}
}
test.go
package main
import (
"bufio"
"encoding/json"
"fmt"
"io"
"log"
"net"
"os"
"strings"
_"time"
)
const (
COMMAND_TRANSFER_FILE = "TRANSFER_FILE"
COMMAND_EXIT = "EXIT"
CONNECTION_TYPE = "tcp"
CONNECTION_PORT = "3645"
CONNECTION_HOST = ""
)
type Command struct {
Identifier string `json:"identifier"`
Name string `json:"name"`
Size int64 `json:"size"`
}
type Result struct {
Message string `json:"message"`
}
func main() {
conn, _ := net.Dial(CONNECTION_TYPE, CONNECTION_HOST + ":" + CONNECTION_PORT)
decoder := json.NewDecoder(conn)
com := Command{}
sourceFileName := ""
destinationFileName := ""
for {
com = Command{}
reader := bufio.NewReader(os.Stdin)
identifier, _ := reader.ReadString('\n')
com.Identifier = strings.TrimSpace(identifier)
switch com.Identifier {
case COMMAND_TRANSFER_FILE:
fmt.Print("Source file name:")
sourceFileName, _ = reader.ReadString('\n')
sourceFileName = strings.TrimSpace(sourceFileName)
fmt.Print("Destination file name:")
destinationFileName, _ = reader.ReadString('\n')
com.Name = strings.TrimSpace(destinationFileName)
file, err := os.Open(sourceFileName)
if err != nil {
log.Fatal(err)
}
defer file.Close()
fileInfo, err := file.Stat()
fileSize := fileInfo.Size()
com.Size = fileSize
case COMMAND_EXIT:
conn.Close()
os.Exit(0)
}
out, _ := json.Marshal(com)
conn.Write([]byte(string(out) + "\n"))
if strings.Compare(com.Identifier, COMMAND_TRANSFER_FILE) == 0 {
file, err := os.Open(sourceFileName)
if err != nil {
log.Fatal(err)
}
defer file.Close()
n, err := io.Copy(conn, file)
if err != nil {
log.Fatal(err)
}
fmt.Println(n, "bytes sent")
}
var msg Result
err := decoder.Decode(&msg)
if err != nil {
fmt.Println(err)
}
fmt.Println(msg)
}
}
私はLinuxとWindowsの両方でそれをテストし、それが両方のシステムで同じ挙動を示しています。私が考えることができるのは、同じマシンで実行しているにもかかわらず、送信者が受信者よりも速いということだけです。そうであれば、ハンドシェーク機構以外の解決策は何でしょうか。
それは私のために働いた:最初に私はサーバーコードを開始し、次にクライアントコードを入力し、次にクライアントの標準入力にTRANSFER_FILEをタイプし、次に64MBのファイル名と宛先名を入力し、 –
同じファイルを複数回連続して転送しようとしましたか? – azizulhakim
ypp https://gist.github.com/gonzaloserrano/1c4bfda42bf8ddfb87cedc62c91b2878 –