I'm new to Go and I'm having troubles debugging this client / server file transfer code. When I request a 719kb png file from the server, I get the 719kb.. but not perfectly, the png when I open it isn't completely displayed (some is cut off. Where am I going wrong here?
// CLIENT ///
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"log"
"net"
"os"
"strings"
)
const BUFFER_SIZE = 1024
func main() {
//get port and ip address to dial
if len(os.Args) != 3 {
fmt.Println("useage example: tcpClient 127.0.0.1 7005")
return
}
var ip string = os.Args[1]
var port string = os.Args[2]
connection, err := net.Dial("tcp", ip+":"+port)
if err != nil {
fmt.Println("There was an error making a connection")
}
//read from
reader := bufio.NewReader(os.Stdin)
fmt.Print("Please enter 'get <filename>' or 'send <filename>' to transfer files to the server\n\n")
inputFromUser, _ := reader.ReadString('\n')
arrayOfCommands := strings.Split(inputFromUser, " ")
if arrayOfCommands[0] == "get" {
getFileFromServer(arrayOfCommands[1], connection)
} else if arrayOfCommands[0] == "send" {
sendFileToServer(arrayOfCommands[1], connection)
} else {
fmt.Println("Bad Command")
}
}
func sendFileToServer(fileName string, connection net.Conn) {
var currentByte int64 = 0
fmt.Println("send to client")
fileBuffer := make([]byte, BUFFER_SIZE)
var err error
//file to read
file, err := os.Open(strings.TrimSpace(fileName)) // For read access.
if err != nil {
connection.Write([]byte("-1"))
log.Fatal(err)
}
connection.Write([]byte("send " + fileName))
//read file until there is an error
for err == nil || err != io.EOF {
_, err = file.ReadAt(fileBuffer, currentByte)
currentByte += BUFFER_SIZE
fmt.Println(fileBuffer)
connection.Write(fileBuffer)
}
file.Close()
connection.Close()
}
func getFileFromServer(fileName string, connection net.Conn) {
var currentByte int64 = 0
fileBuffer := make([]byte, BUFFER_SIZE)
var err error
file, err := os.Create(strings.TrimSpace(fileName))
if err != nil {
log.Fatal(err)
}
connection.Write([]byte("get " + fileName))
for {
connection.Read(fileBuffer)
cleanedFileBuffer := bytes.Trim(fileBuffer, "\x00")
_, err = file.WriteAt(cleanedFileBuffer, currentByte)
currentByte += BUFFER_SIZE
if err == io.EOF {
break
}
}
file.Close()
return
}
// END CLIENT //
// SERVER //
package main
import (
"bytes"
"fmt"
"io"
"log"
"net"
"os"
"strings"
)
const BUFFER_SIZE = 1024
const PORT = "7005"
func main() {
fmt.Println("start listening")
server, error := net.Listen("tcp", "localhost:"+PORT)
if error != nil {
fmt.Println("There was an error starting the server" + error.Error())
return
}
//infinate loop
for {
connection, error := server.Accept()
if error != nil {
fmt.Println("There was am error with the connection" + error.Error())
return
}
fmt.Println("connected")
//handle the connection, on it's own thread, per connection
go connectionHandler(connection)
}
}
func connectionHandler(connection net.Conn) {
buffer := make([]byte, BUFFER_SIZE)
_, error := connection.Read(buffer)
if error != nil {
fmt.Println("There is an error reading from connection", error.Error())
return
}
fmt.Println("command recieved: " + string(buffer))
//loop until disconntect
cleanedBuffer := bytes.Trim(buffer, "\x00")
cleanedInputCommandString := strings.TrimSpace(string(cleanedBuffer))
arrayOfCommands := strings.Split(cleanedInputCommandString, " ")
fmt.Println(arrayOfCommands[0])
if arrayOfCommands[0] == "get" {
sendFileToClient(arrayOfCommands[1], connection)
} else if arrayOfCommands[0] == "send" {
fmt.Println("getting a file")
getFileFromClient(arrayOfCommands[1], connection)
} else {
_, error = connection.Write([]byte("bad command"))
}
}
func sendFileToClient(fileName string, connection net.Conn) {
var currentByte int64 = 0
fmt.Println("send to client")
fileBuffer := make([]byte, BUFFER_SIZE)
//file to read
file, err := os.Open(strings.TrimSpace(fileName)) // For read access.
if err != nil {
log.Fatal(err)
}
var err2 error
//read file until there is an error
for {
_, err2 = file.ReadAt(fileBuffer, currentByte)
currentByte += BUFFER_SIZE
fmt.Println(fileBuffer)
connection.Write(fileBuffer)
if err2 == io.EOF {
break
}
}
file.Close()
return
}
func getFileFromClient(fileName string, connection net.Conn) {
var currentByte int64 = 0
fileBuffer := make([]byte, BUFFER_SIZE)
var err error
file, err := os.Create(strings.TrimSpace(fileName))
if err != nil {
log.Fatal(err)
}
connection.Write([]byte("get " + fileName))
for err == nil || err != io.EOF {
connection.Read(fileBuffer)
cleanedFileBuffer := bytes.Trim(fileBuffer, "\x00")
_, err = file.WriteAt(cleanedFileBuffer, currentByte)
if len(string(fileBuffer)) != len(string(cleanedFileBuffer)) {
break
}
currentByte += BUFFER_SIZE
}
connection.Close()
file.Close()
return
}
// END SERVER //
Together, TCP and IP are the basic standards that define that rules of the Internet and are the most widely used protocols within the Internet protocol suite. However, many major applications rely on TCP such as file transfers (FTP), email, and remote administration.
No, you can't have a TCP server communicating with UDP clients.
Use netcat to establish a connection with the TCP server. By default, netcat will establish a TCP connection with a remote host on the specified port number.
You need to account for the number of bytes returned from ReadAt
, otherwise the last fileBuffer you send will have extra garbage bytes.
Example:
n, err := file.ReadAt(fileBuffer, currentByte)
connection.Write(fileBuffer[:n])
Also bytes.Trim(fileBuffer, "\x00")
will destroy almost any binary file since usually they use null bytes to fill space.
Also the proper way of doing this is just using io.Copy
:
file, err := os.Open(strings.TrimSpace(fileName)) // For read access.
if err != nil {
log.Fatal(err)
}
defer file.Close() // make sure to close the file even if we panic.
n, err = io.Copy(connection, file)
if err != nil {
log.Fatal(err)
}
fmt.Println(n, "bytes sent")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With