In TCP server/client io.CopyN() gets stuck

I am trying to make TCP server for transferring files. I am suing io.CopyN for reading and writing. From server side, I am sending files to client so from server side, it sends perfectly all bytes but Client side after reading a couple of 1000000 bytes it stuck. sometimes it works fine and sometimes it gets stuck. I am using 300 MB pdf to test. Any help, code, and output is like below.

//server

package main

import (
"fmt"
"io"
"log"
"net"
"os"
"strconv"
"strings"
)

func main() {

fmt.Println("In server \n")

ls, err := net.Listen("tcp", ":1234")

defer ls.Close()

if err != nil {

	panic(err)

}

i := 1

for {

	conn, _ := ls.Accept()
	var check string
	var check1 string

	defer conn.Close()

	for {
		fmt.Println("Do you want to send more : ")
		fmt.Scanf("%s", &check1)

		if check == "n" {

			break

		}

		file, err := os.Open(strings.TrimSpace("./" + "Mag" + ".pdf"))

		if err != nil {

			fmt.Println("inside error 111 : ", i)
			log.Fatal(err)
		}

		defer file.Close()

		fileInfo, err := file.Stat()

		if err != nil {

			fmt.Println("in stat")
		}

		size := fileInfo.Size()

		numberOfTime := size / 1000000

		leftByte := size - numberOfTime*1000000

		numberOfTimeString := strconv.Itoa(int(numberOfTime))
		leftByteString := strconv.Itoa(int(leftByte))

		fmt.Println("1000000 times : ", numberOfTimeString)

		fmt.Println("Left Bytes : ", leftByteString)

		sizeSent, err := fmt.Fprintf(conn, numberOfTimeString+"\n")

		if err != nil {

			panic(err)

		}

		sizeSent, err = fmt.Fprintf(conn, leftByteString+"\n")

		if err != nil {

			panic(err)

		}

		fmt.Println(sizeSent)

		fileWriter := io.Writer(conn)

		n, err := io.CopyN(fileWriter, file, size)

		if err == io.EOF {
			fmt.Println(err, n)
		}

		fmt.Println(n, "bytes sent")

		if err != nil {

			log.Println(err)

		}

		file.Close()

	}

}

fmt.Println("We are done with server")

}

//client

  //client

package main

 import (
"bufio"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"os"
"os/signal"
"strconv"
"strings"
"syscall"
 )

func main() {

c := make(chan os.Signal, 15)
signal.Notify(c, syscall.SIGINT)

go func() {

	for {
		s := <-c

		switch s {

		case syscall.SIGINT:
			removeDir()
			os.Exit(1)
		}

	}

}()

defer removeDir()

conn, err := net.Dial("tcp", ":1234")

if err != nil {

	panic(err)

}

defer conn.Close()

connReadWrite := bufio.NewReader(io.Reader(conn))

var i int
var filename string

for {

	i++
	if i > 15 {
		break
	}

	nu := strconv.Itoa(i)
	os.MkdirAll("./"+nu+"/", os.ModePerm)

	filename = "./" + nu + "/image" + nu + ".pdf"

	file, err := os.Create(filename)

	defer file.Close()

	if err != nil {
		panic(err)
	}

	l1, err := connReadWrite.ReadString('\n')

	if err != nil {

		println(err)
	}

	println("\n1000000 times :", l1)

	l1 = strings.TrimSuffix(l1, "\n")

	nb1, err := strconv.Atoi(l1)

	if err != nil {

		panic(err)
	}

	l2, err := connReadWrite.ReadString('\n')

	if err != nil {

		println(err)
	}

	println("Left Bytes :", l2)

	l2 = strings.TrimSuffix(l2, "\n")

	nb2, err := strconv.Atoi(l2)

	if err != nil {

		panic(err)
	}

	fmt.Println("After convert in Num :", nb1, nb2)

	newFileWriter := io.Writer(file)
	newFileReader := io.Reader(conn)

	for i := 0; i < nb1; i++ {

		n, err := io.CopyN(newFileWriter, newFileReader, 1000000)

		if i >= 31 {
			errFun(err, n)
		}
	}

	n, err := io.CopyN(newFileWriter, newFileReader, int64(nb2))
	errFun(err, n)

	file.Close()

}

fmt.Println("We are done with client ")
}

func errFun(err error, n int64) {

if err == io.EOF {

	fmt.Println("End of file : ", n)
	return

} else if n == 0 {

	fmt.Println("n is : ", n)
	return

} else if err != nil {
	fmt.Println(err)
	return

}

fmt.Println(err, " : ", n)
}

func removeDir() {

var dir []string

files, err := ioutil.ReadDir("./")
if err != nil {
	log.Fatal(err)
}

for _, f := range files {
	dir = append(dir, f.Name())
}

for i, dname := range dir {

	if i < 1 {
		continue
	}

	file, err := os.Open("./" + dname)

	fileInfo, err := file.Stat()

	if !fileInfo.IsDir() {

		file.Close()
		continue

	}

	err = os.RemoveAll(dname)

	if err != nil {
		log.Fatal(err)
	}

	file.Close()

}

input/output

from server side when press Y it sends data after the client side it gets a number of bytes it needs to read and then I am sending the file and then it read. In the picture, I was able to send two-time third time it got stuck sometimes it stuck first time too. when stuck if press cnt+C it gets End of file err. i just don’t understand this

I can see lot’s of people watched this question but Why no one replying back… do I need to make any changes in My question if yes then please let me know I really want to solve this problem

In the screen capture you posted, did you not see the error message from the client that said you got a panic because you sent strconv.Atoi() bad data? Try checking the data you pass to strconv.Atoi() before calling it, and have your program issue more detailed messages when things don’t go right. Then when there is an error, it will point you to the exact line of code where things went wrong.

I copied both client and server from your post, and ran them. I saw that about 1/3 of the time, the client failed with that same error message. (I never saw it get “stuck”, just that.)

The problem is at the strconv.Atoi() call at line number 90 in the client. Instead of getting a string holding an integer, like “835474”, it’s getting a very long string full of junk that it cannot parse.

By the way, the code you posted for the client is missing a ‘}’ at the end. When you post, you can check the code you posted to make sure it’s correct by copying it back into a .go file and make sure it compiles/runs. Don’t post code that won’t compile and then wonder why no one replied.

Thanks for the reply and sorry for all the thing that you mentioned. I will keep in mind. Actually, I posted it on stack overflow and I got the solution.
https://stackoverflow.com/questions/52233610/client-stuck-when-trying-to-read-with-io-copyn-in-golang/52239522#52239522

And about sticking program, you couldn’t see it, but let me explain to you If client read successfully it goes the second time to read and at the same time server keep send data one by one. and one important thing is that I am using io.copyN() so it won’t come out until it reads N byte or EOF so In my program, sometimes it stuck in while it reading some last bytes and that time it doesn’t get EOF and Not read N byte. but at the same time server is sending data so new data come to buffer it reads it and come out from the io.copyN() and so the number server send (file size) it read by io.copyN() and after then the file will be read by

 l1, err := connReadWrite.ReadString('\n')

and it got data which it can’t convert and it panics. I have removed some code cause on stack overflow some people told me to remove extra code. and that’s why you can’t see when it actually stuck :slight_smile: I have tried other reader too like ReadFull(), ReadAtLeast(), etc… but all stuck there…

The problem was not strconv() the real problem was I had wrapped up conn first time

   connReadWrite := bufio.NewReader(io.Reader(conn))  

and then after using it two times, I was creating another reader wrapper for conn

  newFileWriter := io.Writer(file)
  newFileReader := io.Reader(conn)

for reading the real file and that’s the wrong thongs to do I have deleted new wrapper and used the old one in

 n, err := io.CopyN(file,   connReadWrite , 1000000)

and it worked.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.