[Go] Try TCP 1
Tags: go
Published: 2023-09-13 17:18:20

## Intro
In this time, I will try sending and receiving data using TCP.
Also, I will try watching the packets at that time using Wireshark.

### Environments
* Go ver.1.21.0
* Wireshark ver.4.0.8

## Sample projects
### [Client] main.go
```go
package main

import (
	"fmt"
	"log"
	"net"
)

func main() {
	var conn net.Conn
	var err error
	defer func() {
		if conn != nil {
			conn.Close()
		}
	}()
	buf := make([]byte, 1024)
	conn, err = net.Dial("tcp", ":5055")
	if err != nil {
		log.Panicln(err.Error())
	}
	data := []byte(fmt.Sprintln("Hello1"))
	_, err = conn.Write(data)
	if err != nil {
		log.Panicln(err.Error())
	}
	leng, err := conn.Read(buf)
	if err != nil {
		log.Panicln(err.Error())
	}
	log.Println(string(buf[:leng]))
}

```

#### [Server] main.go
```go
package main

import (
	"fmt"
	"log"
	"net"
)

func main() {
	socket, err := net.Listen("tcp", "localhost:5055")
	if err != nil {
		log.Fatal(err.Error())
	}
	defer socket.Close()
	conn, err := socket.Accept()
	if err != nil {
		log.Fatal(err.Error())
	}
	defer conn.Close()
	for {
		buf := make([]byte, 1024)
		length, err := conn.Read(buf)
		if err != nil {
			log.Fatal(err.Error())
		}
		result := ""
		for i := 0; i < length; i++ {
			result = fmt.Sprintf("%s %02X", result, buf[i])
		}
		log.Println(result)
		log.Println(string(buf[:length]))
		_, err = conn.Write([]byte(fmt.Sprintf("Received: %d", length)))
		if err != nil {
			log.Fatal(err.Error())
		}
	}
}
```

#### [Client] Result
```
2023/09/13 01:26:23 Received: 7
```

#### [Server] Results
```
2023/09/13 01:26:23  48 65 6C 6C 6F 31 0A
2023/09/13 01:26:23 Hello1

2023/09/13 01:26:24 EOF
exit status 1
```

## Watching packets
I will try following the flow of the above processing from the packets captured with Wireshark.

### Connecting
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lqupw8c8fbxlclboua2x.png)

1. First, establish a TCP connection using 3-way handshake.
	At that time, each application generates a Sequence Number and sends it to the other party with the SYN or ACK flags.
2. After receiving the number, they add 1 to it and hold it as an Acknowledgment Number.
	The value is the number that the application expects to be sent as the next Sequence Number.
3. Now, both have the same values.

### Send text data

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7zmn3ismtyx9ojjbhm90.png)

1. The client sends text data(7 bytes) to the server.
2. The server receives them and adds 7 to the last Acknowledgment Number and hold it as new one.
3. Now, both have the same values.

## How to get the received data length?
To get new Acknowledge Number, the receiver has to get the received data length.
But according to [RFC9293](https://datatracker.ietf.org/doc/html/rfc9293), the TCP header doesn't have data length.
It only has TCP header length(== Data Offset).

According to [RFC791](https://datatracker.ietf.org/doc/html/rfc791), the IP header has total length and IP header length.

```
Total Length(47) - (IP header length(5 * 4) + TCP header length(5 * 4)) = 7(bytes)  
```

## Sending data repeatedly in a short period of time
When I try sending data repeatedly in a short period of time, all of the received data will be merged.

### [Client] main.go
```go
...
func main() {
	var conn net.Conn
	var err error
	defer func() {
		if conn != nil {
			conn.Close()
		}
	}()
	buf := make([]byte, 1024)
	conn, err = net.Dial("tcp", ":5055")
	if err != nil {
		log.Panicln(err.Error())
	}
	data := []byte(fmt.Sprintln("Hello1"))
	_, err = conn.Write(data)
	if err != nil {
		log.Panicln(err.Error())
	}
	// second
	data = []byte(fmt.Sprintln("Hello2"))
	_, err = conn.Write(data)
	if err != nil {
		log.Panicln(err.Error())
	}
	// Third
	data = []byte(fmt.Sprintln("Hello3"))
	_, err = conn.Write(data)
	if err != nil {
		log.Panicln(err.Error())
	}
	leng, err := conn.Read(buf)
	if err != nil {
		log.Panicln(err.Error())
	}
	log.Println(string(buf[:leng]))
}
```

#### [Client] Result
```
2023/09/13 01:26:23 Received: 21
```

#### [Server] Results
```
2023/09/14 02:01:25  48 65 6C 6C 6F 31 0A 48 65 6C 6C 6F 32 0A 48 65 6C 6C 6F 33 0A
2023/09/14 02:01:25 Hello1
Hello2
Hello3

2023/09/14 02:01:25 EOF
exit status 1
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x430bevvjhhlkkmwr11z.png)

To avoid that, I can change the buffer size to 7, because all of the data have same length.

#### [Server] main.go
```go
...
func main() {
...
	defer conn.Close()
	for {
		buf := make([]byte, 7)
		length, err := conn.Read(buf)
		if err != nil {
			log.Fatal(err.Error())
		}
		result := ""
		for i := 0; i < length; i++ {
			result = fmt.Sprintf("%s %02X", result, buf[i])
		}
		log.Println(result)
		log.Println(string(buf[:length]))
		_, err = conn.Write([]byte(fmt.Sprintf("Received: %d", length)))
		if err != nil {
			log.Fatal(err.Error())
		}
	}
}
```


#### [Client] Result
```
2023/09/13 01:26:23 Received: 7
```

#### [Server] Results
```
2023/09/14 02:10:50  48 65 6C 6C 6F 31 0A
2023/09/14 02:10:50 Hello1

2023/09/14 02:10:50  48 65 6C 6C 6F 32 0A
2023/09/14 02:10:50 Hello2

2023/09/14 02:10:50  48 65 6C 6C 6F 33 0A
2023/09/14 02:10:50 Hello3

2023/09/14 02:10:50 read tcp 127.0.0.1:5055->127.0.0.1:52505: wsarecv: An existing connection was forcibly closed by the remote host.
exit status 1
```

## Resources
* [RFC9293 - Transmission Control Protocol (TCP)](https://datatracker.ietf.org/doc/html/rfc9293)
* [RFC791 - INTERNET PROTOCOL](https://datatracker.ietf.org/doc/html/rfc791)
* [TCP技術入門](https://gihyo.jp/book/2019/978-4-297-10623-2)