Attempt to do TLS over UDP: wsarecv error about large message - go

I want get tls conn base on udp, just like:
package main
import (
"crypto/tls"
"fmt"
"io"
"net"
"time"
)
func handleConn(conn net.Conn) {
defer conn.Close()
var buf []byte = make([]byte, 2000)
for {
if n, err := conn.Read(buf); err != nil && err != io.EOF {
panic(err)
} else {
conn.Write(buf[:n])
}
}
}
func server() {
cert, err := tls.LoadX509KeyPair("./serve.cert.pem", "./serve.key.pem")
if err != nil {
panic(err)
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19986}, &net.UDPAddr{Port: 19987})
if err != nil {
panic(err)
}
tconn := tls.Server(conn, config)
defer tconn.Close()
if err = tconn.Handshake(); err != nil {
panic(err)
}
handleConn(tconn)
}
func main() {
go server()
time.Sleep(time.Second)
client()
}
func client() {
conf := &tls.Config{
InsecureSkipVerify: true,
}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19987}, &net.UDPAddr{Port: 19986})
if err != nil {
panic(err)
}
tconn := tls.Client(conn, conf)
defer tconn.Close()
if err = tconn.Handshake(); err != nil {
panic(err)
}
_, err = conn.Write([]byte("hello"))
if err != nil {
panic(err)
}
buf := make([]byte, 100)
n, err := conn.Read(buf)
if err != nil {
panic(err)
}
fmt.Println(string(buf[:n]))
}
panic:
panic: read udp 127.0.0.1:19987->127.0.0.1:19986: wsarecv: A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself.
goroutine 1 [running]:
main.client()
D:/OneDrive/code/go/ctest/main.go:65 +0x2d1
main.main()
D:/OneDrive/code/go/ctest/main.go:49 +0x34
exit status 2
Appendix:
serve.cert.pem
-----BEGIN CERTIFICATE-----
MIIBbjCCARSgAwIBAgIRAI+jBYEYS5aBXDUedBt7PKYwCgYIKoZIzj0EAwIwEjEQ
MA4GA1UEChMHQWNtZSBDbzAeFw0yMjAxMDkxNzQxMjBaFw0yMzAxMDkxNzQxMjBa
MBIxEDAOBgNVBAoTB0FjbWUgQ28wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQy
l1/gWhTxZ3rS/XJOMLHhmkQp64EtPrEgq9SjKDpWBZQC+kNZdM5xzJrv3bLqcyOS
JywZfEpTZzW7sxko4maBo0swSTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYI
KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAUBgNVHREEDTALgglsb2NhbGhvc3QwCgYI
KoZIzj0EAwIDSAAwRQIhAICxMC8o603GwL3bf42EXrtPP5/LtEIc/hjdJpilqc3b
AiBTEdrE+/oCgUjsxV2RFj1+42CTGtcav4sJyCPjme0N/w==
-----END CERTIFICATE-----
serve.key.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmH+BleetLN1fK0dy
JpedWG8C2yxtb7gEEAwvdwXf6FihRANCAAQyl1/gWhTxZ3rS/XJOMLHhmkQp64Et
PrEgq9SjKDpWBZQC+kNZdM5xzJrv3bLqcyOSJywZfEpTZzW7sxko4maB
-----END PRIVATE KEY-----
I try set udp conn's buff, useless!
The certificate only 558 Bytes, but the UDP has a capacity of 65536 Bytes. then, I debug found: in crypt/tls/conn.go>readRecordOrCCS c.readFromUntil(c.conn, recordHeaderLen), the recordHeaderLen is constant 5, it add bytes.MinRead; so the reader buff's len is 517. Actually data size about 700 Bytes.
So? What should I do?

You cannot sensibly expect to make the thing work: TLS (and SSL) is designed to be carried out using the application layer of another protocol.
What this means in simpler terms is that while TLS is oblivious to what particular protocol transports its bytes, as a client of the application layer, it expects two properties from the underlying stack: it transports arbitrary opaque streams of data, ensuring robustness and in-order delivery.
In the TCP/IP world, this means TCP because UDP does not provide neither of the properties TLS expects.
Still, some solutions do successfully employ TLS over UDP, with OpenVPN being a prime example of this—it uses TLS for handshake and initial key exchange while having UDP as its default, and recommended, transport protocol,—but all of them have a layer implemented over UDP which "arms" it with the properties typically found in TCP: such layers deal with dropped, reordered, duplicated and corrupted UDP frames, "exporting" to the upper layer a protocol which is OK to use for application layer.
This basically means than if you're after using TLS over UDP, you first need to implemet a custom type having the net.Conn interface which would use a UDP association to shovel the bytes back and forth and "export" to its client a connection which has the properties of robustness and in-order delivery—just as net.TCPConn does.

I GOT IT!
just make udp conn become to stream io.
package main
import (
"bufio"
"crypto/tls"
"fmt"
"io"
"net"
"time"
)
func handleConn(conn net.Conn) {
defer conn.Close()
var buf []byte = make([]byte, 2000)
for {
if n, err := conn.Read(buf); err != nil && err != io.EOF {
panic(err)
} else {
fmt.Println(string(buf[:n]))
conn.Write(append([]byte("got: "), buf[:n]...))
}
}
}
func server() {
cert, err := tls.LoadX509KeyPair("./serve.cert.pem", "./serve.key.pem")
if err != nil {
panic(err)
}
config := &tls.Config{Certificates: []tls.Certificate{cert}}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19986}, &net.UDPAddr{Port: 19987})
if err != nil {
panic(err)
}
sconn := NewSconn(conn)
tconn := tls.Server(sconn, config)
defer tconn.Close()
handleConn(tconn)
}
func main() {
go server()
time.Sleep(time.Second)
client()
}
func client() {
conf := &tls.Config{
InsecureSkipVerify: true,
CipherSuites: []uint16{
tls.TLS_AES_128_GCM_SHA256,
},
}
conn, err := net.DialUDP("udp", &net.UDPAddr{Port: 19987}, &net.UDPAddr{Port: 19986})
if err != nil {
panic(err)
}
sconn := NewSconn(conn)
tconn := tls.Client(sconn, conf)
defer tconn.Close()
_, err = tconn.Write([]byte("hello"))
if err != nil {
panic(err)
}
buf := make([]byte, 100)
n, err := tconn.Read(buf)
if err != nil {
panic(err)
}
fmt.Println(string(buf[:n]))
}
//
//
//
//
// --------------------------------------------------
type sconn struct {
conn net.Conn
buf *bytes.Buffer
rLen int
lock sync.Mutex
}
func NewSconn(conn net.Conn) *sconn {
return &sconn{
conn: conn,
buf: bytes.NewBuffer(nil),
rLen: 2000,
lock: sync.Mutex{},
}
}
func (s *sconn) Read(b []byte) (n int, err error) {
s.lock.Lock()
defer s.lock.Unlock()
if s.buf.Len() != 0 {
n, err = s.buf.Read(b)
} else {
s.push(&s.rLen)
n, err = s.buf.Read(b)
}
return n, err
}
// push push UDP package to buff
func (s *sconn) push(rLen *int) (err error) {
defer func() {
if e := recover(); e != nil {
if *rLen < 65536 {
*rLen = *rLen + 2000
s.push(rLen)
} else {
err = errors.New(fmt.Sprintln(e))
}
}
}()
var tmp []byte = make([]byte, *rLen)
if n, err := s.conn.Read(tmp); err != nil {
return err
} else {
_, err := s.buf.Write(tmp[:n])
return err
}
}
func (s *sconn) Write(b []byte) (n int, err error) {
for i := 0; i < len(b); i = i + 512 {
j := i + 512
if j > len(b) {
j = len(b)
}
if n, err = s.conn.Write(b[i:j]); err != nil {
return n, err
}
}
return len(b), nil
}
func (s *sconn) Close() error { return nil } // only close TLS conn, don't close UDP conn
func (s *sconn) LocalAddr() net.Addr { return s.conn.LocalAddr() }
func (s *sconn) RemoteAddr() net.Addr { return s.conn.RemoteAddr() }
func (s *sconn) SetDeadline(t time.Time) error { return s.conn.SetDeadline(t) }
func (s *sconn) SetReadDeadline(t time.Time) error { return s.conn.SetReadDeadline(t) }
func (s *sconn) SetWriteDeadline(t time.Time) error { return s.conn.SetWriteDeadline(t) }

Related

Cannot receive response packets from multicast server in golang

I setup a udp server listening multicast trafic, and create a client to sent test packet. When the server receives the package, it will send a response. Everything is ok, except the client cannot receive the packet from the server. Why?
package main
import (
"log"
"net"
"os"
"time"
"golang.org/x/net/ipv4"
)
func SetupMulticast(ifn, addr string) {
ifi, err := net.InterfaceByName(ifn)
if err != nil {
log.Fatal(err)
}
//server
c, err := net.ListenPacket("udp4", addr)
if err != nil {
log.Fatal(err)
}
log.Printf("listen ad:%s\n", addr)
p := ipv4.NewPacketConn(c)
gAddr, err2 := net.ResolveUDPAddr("udp4", addr)
if err2 != nil {
log.Fatal(err2)
}
if err := p.JoinGroup(ifi, gAddr); err != nil {
log.Fatal(err)
}
if err := p.SetControlMessage(ipv4.FlagDst|ipv4.FlagSrc, true); err != nil {
log.Fatal(err)
}
go func() {
b := make([]byte, 1500)
for {
n, cm, src, err := p.ReadFrom(b)
if err != nil {
break
}
log.Println("receive:", string(b[:n]), cm.Dst.IsMulticast(), cm.Dst)
if n2, err := p.WriteTo([]byte("world!"), nil, src); err != nil {
log.Printf("fail to write back:%v\n", err)
} else {
log.Printf("write back addr: %s length:%d\n", src, n2)
}
}
}()
//client
if conn, err2 := net.DialUDP("udp4", nil /*src*/, gAddr); err2 != nil {
log.Fatal(err)
} else {
go func() {
for {
log.Println("write hello...")
conn.Write([]byte("hello"))
time.Sleep(time.Second * 2)
}
}()
go func() {
b2 := make([]byte, 1500)
for {
n, err := conn.Read(b2)
if err != nil {
log.Panic(err)
}
log.Printf("sender received response:%s\n", string(b2[:n]))
}
}()
}
}
func main() {
If := os.Args[1] //ens33
Addr := os.Args[2] //224.0.0.248:1025
SetupMulticast(If, Addr)
for {
}
}
And the output:
2022/08/17 22:53:53 listen ad:224.0.0.248:1025
2022/08/17 22:53:53 write hello...
2022/08/17 22:53:53 receive: hello true 224.0.0.248
2022/08/17 22:53:53 write back addr: 192.168.19.131:43925 length:6
2022/08/17 22:53:55 write hello...
2022/08/17 22:53:55 receive: hello true 224.0.0.248
2022/08/17 22:53:55 write back addr: 192.168.19.131:43925 length:6
From the logs, there are no any "sender received response" record. I don't know why?

go - Simple worker pool

As a beginner in go and programming in general, I've been coding a port scanner in go with gopacket library and most of the code is done, but I've been running into a problem of spawning too many goroutines and getting 'read ip4 0.0.0.0: i/o timeout' I've done some research and it seems I need to implement a worker pool I've been trying to implement this example 'https://gobyexample.com/worker-pools' as I'm still learning goroutines and channels I've been at it a few days now and can't seem to figure out how to implement the above example correctly in my program can you guys give me some pointers or preferably a code fix example.
package main
import (
"fmt"
"log"
"net"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/layers"
)
// Get preferred outbound ip and port of this machine
func GetOutboundIPPort() (net.IP, int) {
conn, err := net.Dial("udp", "1.1.1.1:80")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
localAddr := conn.LocalAddr().(*net.UDPAddr)
return localAddr.IP, localAddr.Port
}
func ipv4_gen(out chan net.IP) {
ip, ipnet, err := net.ParseCIDR("192.168.0.0/24")
if err != nil {
log.Fatal(err)
}
for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) {
time.Sleep(300 * time.Millisecond)
dstaddrs, err := net.LookupIP(ip.String())
if err != nil {
log.Fatal(err)
}
dstip := dstaddrs[0].To4()
out <- dstip
}
close(out)
}
func inc(ip net.IP) {
for j := len(ip) - 1; j >= 0; j-- {
ip[j]++
if ip[j] > 0 {
break
}
}
}
func port_scanner(dstip net.IP) {
dstport := layers.TCPPort(80)
srcip, port := GetOutboundIPPort()
srcport := layers.TCPPort(port)
ip := &layers.IPv4{
SrcIP: srcip,
DstIP: dstip,
Protocol: layers.IPProtocolTCP,
}
tcp := &layers.TCP{
SrcPort: srcport,
DstPort: dstport,
Seq: 1105024978,
SYN: true,
Window: 14600,
}
tcp.SetNetworkLayerForChecksum(ip)
buf := gopacket.NewSerializeBuffer()
opts := gopacket.SerializeOptions{
ComputeChecksums: true,
FixLengths: true,
}
if err := gopacket.SerializeLayers(buf, opts, tcp); err != nil {
log.Fatal(err)
}
conn, err := net.ListenPacket("ip4:tcp", "0.0.0.0")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
if _, err := conn.WriteTo(buf.Bytes(), &net.IPAddr{IP: dstip}); err != nil {
log.Fatal(err)
}
// Set deadline so we don't wait forever.
if err := conn.SetDeadline(time.Now().Add(10 * time.Second)); err != nil {
log.Fatal(err)
}
for {
b := make([]byte, 4096)
n, addr, err := conn.ReadFrom(b)
if err != nil {
log.Println("error reading packet: ", err)
return
} else if addr.String() == dstip.String() {
// Decode a packet
packet := gopacket.NewPacket(b[:n], layers.LayerTypeTCP, gopacket.Default)
// Get the TCP layer from this packet
if tcpLayer := packet.Layer(layers.LayerTypeTCP); tcpLayer != nil {
tcp, _ := tcpLayer.(*layers.TCP)
if tcp.DstPort == srcport {
if tcp.SYN && tcp.ACK {
fmt.Printf("Discovered open port %d/tcp on %s\n", dstport, dstip)
}
return
}
}
}
}
}
func worker(id int, ips <-chan net.IP) {
for ip := range ips {
go port_scanner(ip)
}
}
func main() {
ips := make(chan net.IP)
go ipv4_gen(ips)
for w := 1; w <= 10; w++ {
go worker(w, ips)
}
}
You are starting a new goroutine for each piece of work inside the worker so it defeats its purpose.
You need to run the work instead of starting a goroutine inside the worker.

Simple server client communication not working

This seemingly simple example is not working as expected and I feel bad for asking but here goes:
There's a client that retries connecting to the server, sends a message, and then waits for a response:
func client() {
var conn net.Conn
var err error
// retry server until it is up
for {
conn, err = net.Dial("tcp", ":8081")
if err == nil {
break
}
log.Println(err)
time.Sleep(time.Second)
}
// write to server
_, err = conn.Write([]byte("request"))
if err != nil {
log.Println(err)
return
}
// block & read from server
var buf []byte
n, err := conn.Read(buf)
if err != nil {
log.Println(err)
return
}
log.Printf("From server: %s\n", buf[:n])
}
It connects to a server which for each connection, reads and interprets the sent data, and sends a response if needed:
func server() {
ln, _ := net.Listen("tcp", ":8081")
for {
conn, _ := ln.Accept()
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
var buf []byte
n, err := conn.Read(buf)
if err != nil {
return
}
log.Printf("Server got: %s\n", buf)
if string(buf[:n]) == "request" {
_, _ = conn.Write([]byte("response"))
}
}
All driven by the main function:
func main() {
go client()
server()
}
Error handling is omitted for brevity. The expected behavior is that the client will connect to the server and send the message "request" and then block on the read. The server receives "request" and sends the message "response" back to the same connection. The client unblock, prints the received message and exits. Instead, when the program is run, the following is printed:
2019/09/01 22:24:02 From server:
2019/09/01 22:24:02 Server got:
Suggesting that no data was exchanged, and that the client did not block.
The looping in client is strange!
The looping not make sense if read/write is out.
But the error is only this:
//var buf []byte <--- this read 0 bytes
buf := make([]byte, 1024)
n, err := conn.Read(buf)
A proposal for you:
package main
import (
"log"
"net"
"time"
)
func client() {
var conn net.Conn
var err error
// retry server until it is up
for {
log.Printf("Connecting...")
conn, err = net.Dial("tcp", ":8082")
if err != nil {
log.Println(err)
break
}
time.Sleep(time.Second)
// write to server
log.Printf("Writing...")
_, err = conn.Write([]byte("request"))
if err != nil {
log.Println(err)
return
}
// block & read from server
log.Printf("Reading...")
var buf []byte
n, err := conn.Read(buf)
if err != nil {
log.Println(err)
return
}
log.Printf("From server: %s\n", buf[:n])
}
}
func server() {
ln, _ := net.Listen("tcp", ":8082")
for {
conn, _ := ln.Accept()
go handleConn(conn)
}
}
func handleConn(conn net.Conn) {
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
return
}
log.Printf("Server got: [%d bytes] %s\n", n, buf)
if string(buf[:n]) == "request" {
_, _ = conn.Write([]byte("response"))
}
conn.Close()
}
func main() {
go client()
server()
}

TCP connection returns 'broken pipe' error when used multiple times

This question relates to go and its net package.
I wrote a simple tcp server handles some RPC. the client is using a chan net.Conn to manage all tcp connection on the client side. Server is running with a tcp listener.
here's the code:
client:
package server
import (
"errors"
"log"
"net"
)
var tcpPool chan net.Conn
func NewClient(connections int, address string) {
tcpPool = make(chan net.Conn, connections)
for i := 0; i < connections; i++ {
conn, err := net.Dial("tcp4", address)
if err != nil {
log.Panic(err)
}
tcpPool <- conn
}
}
func SendMessage(msg []byte) ([]byte, error) {
conn := getConn()
log.Println("check conn: ", conn)
log.Println("msg: ", msg)
defer releaseConn(conn)
// send message
n, err := conn.Write(msg)
if err != nil {
log.Panic(err)
} else if n < len(msg) {
log.Panic(errors.New("Message did not send in full"))
}
// receiving a message
inBytes := make([]byte, 0)
for {
// bufsize 1024, read bufsize bytes each time
b := make([]byte, bufSize)
res, err := conn.Read(b)
log.Println("server sends >>>>>>>>>>>>: ", res)
if err != nil {
b[0] = ReError
break
}
inBytes = append(inBytes, b[:res]...)
// message finished.
if res < bufSize {
break
}
}
// check replied message
if len(inBytes) == 0 {
return []byte{}, errors.New("empty buffer error")
}
log.Println("SendMessage gets: ", inBytes)
return inBytes, nil
}
func releaseConn(conn net.Conn) error {
log.Println("return conn to pool")
select {
case tcpPool <- conn:
return nil
}
}
func getConn() (conn net.Conn) {
log.Println("Take one from pool")
select {
case conn := <-tcpPool:
return conn
}
}
server
func StartTCPServer(network, addr string) error {
listener, err := net.Listen(network, addr)
if err != nil {
return errors.Wrapf(err, "Unable to listen on address %s\n", addr)
}
log.Println("Listen on", listener.Addr().String())
defer listener.Close()
for {
log.Println("Accept a connection request.")
conn, err := listener.Accept()
if err != nil {
log.Println("Failed accepting a connection request:", err)
continue
}
log.Println("Handle incoming messages.")
go onConn(conn)
}
}
//onConn recieves a tcp connection and waiting for incoming messages
func onConn(conn net.Conn) {
inBytes := make([]byte, 0)
defer func() {
if e := recover(); e != nil {
//later log
if err, ok := e.(error); ok {
println("recover", err.Error())
}
}
conn.Close()
}()
// load msg
for {
buf := make([]byte, bufSize)
res, err := conn.Read(buf)
log.Println("server reading: ", res)
inBytes = append(inBytes, buf[:res]...)
if err != nil || res < bufSize {
break
}
}
var req RPCRequest
err := json.Unmarshal(inBytes, &req)
if err != nil {
log.Panic(err)
}
log.Println("rpc request: ", req)
var query UserRequest
err = json.Unmarshal(req.Query, &query)
if err != nil {
log.Panic(err)
}
log.Println("rpc request query: ", query)
// call method to process request
// good now we can proceed to function call
// some actual function calls gets a output
// outBytes, err := json.Marshal(out)
conn.Write(outBytes)
}
I think this is very standard. but for some reason, I can only send message on the client side one, and then the follow 2nd and 3rd start to show some irregularity.
1st ---> success, gets response
2nd ---> client can send but nothing gets back, logs on server side shows no in coming message
3rd ---> if I send from client side one more time, it shows broken pipe error..
There are some bad handling way.
First, the flag to insure the msg from server finished is depending on io.EOF,not length
// message finished.
if res < 512 {
break
}
instead of this, reader returns an io.EOF is the only symbol that shows message finished.
Second, chan type has its property to block and not need to use select.by the way, you really need to start a goroutine to release. The same requirement for getConn
func releaseConn(conn net.Conn) {
go func(){
tcpPool <- conn
}()
}
func getConn() net.Conn {
con := <-tcpPool
return con
}
Third, listener should not be close, code below is bad
defer listener.Close()
The most important reason is
on the client side,
res, err := conn.Read(b) this receive the reply from the server.
when nothing reply ,it block rather than io.EOF, nor some error else.
It means ,you cann't box a lasting communicating part into a function send().
You can do a single thing to use sendmsg() to send, but never use sendmsg() to handle the reply.
you can handle reply like this
var receive chan string
func init() {
receive = make(chan string, 10)
}
func ReceiveMessage(con net.Conn) {
// receiving a message
inBytes := make([]byte, 0, 1000)
var b = make([]byte, 512)
for {
// bufsize 1024, read bufsize bytes each time
res, err := con.Read(b)
if err != nil {
if err == io.EOF {
break
}
fmt.Println(err.Error())
break
}
inBytes = append(inBytes, b[:res]...)
msg := string(inBytes)
fmt.Println("receive msg from server:" + msg)
receive <- msg
}
}
I found several problem in your code, but I can't tell which one leads your failure.
This is my code according to what you write and did some fixing.
client.go:
package main
import (
"fmt"
"io"
"log"
"net"
)
var tcpPool chan net.Conn
var receive chan string
func init() {
receive = make(chan string, 10)
}
func NewClient(connections int, address string) {
tcpPool = make(chan net.Conn, connections)
for i := 0; i < connections; i++ {
conn, err := net.Dial("tcp", address)
if err != nil {
log.Panic(err)
}
tcpPool <- conn
}
}
func SendMessage(con net.Conn, msg []byte) error {
// send message
_, err := con.Write(msg)
if err != nil {
log.Panic(err)
}
return nil
}
func ReceiveMessage(con net.Conn) {
// receiving a message
inBytes := make([]byte, 0, 1000)
var b = make([]byte, 512)
for {
// bufsize 1024, read bufsize bytes each time
res, err := con.Read(b)
if err != nil {
if err == io.EOF {
break
}
fmt.Println(err.Error())
break
}
inBytes = append(inBytes, b[:res]...)
msg := string(inBytes)
fmt.Println("receive msg from server:" + msg)
receive <- msg
}
}
func getConn() net.Conn {
con := <-tcpPool
return con
}
func main() {
NewClient(20, "localhost:8101")
con := <-tcpPool
e := SendMessage(con, []byte("hello, i am client"))
if e != nil {
fmt.Println(e.Error())
return
}
go ReceiveMessage(con)
var msg string
for {
select {
case msg = <-receive:
fmt.Println(msg)
}
}
}
server.go
package main
import (
"fmt"
"io"
"net"
)
func StartTCPServer(network, addr string) error {
listener, err := net.Listen(network, addr)
if err != nil {
return err
}
for {
conn, err := listener.Accept()
if err != nil {
fmt.Println(err.Error())
continue
}
onConn(conn)
}
}
//onConn recieves a tcp connection and waiting for incoming messages
func onConn(conn net.Conn) {
inBytes := make([]byte, 0)
// load msg
for {
buf := make([]byte, 512)
res, err := conn.Read(buf)
if err != nil {
if err == io.EOF {
return
}
fmt.Println(err.Error())
return
}
inBytes = append(inBytes, buf[:res]...)
fmt.Println("receive from client:" + string(inBytes))
conn.Write([]byte("hello"))
}
}
func main() {
if e := StartTCPServer("tcp", ":8101"); e != nil {
fmt.Println(e.Error())
return
}
}
this works and no error.
By the way, I can't see where either on the client side or the server side you do con.Close(). It's nessasary to close it.This means a connection once got from the pool, you don't put it back. When you think a connection is over, then close it and build a new connection to fill the pool rather than put it back,beause it's a fatal operation to put a closed con back to the pool.

Golang TCPConn Gob Communication

I'm having issues with the gob protocol (or maybe networking in general, where my knowledge is weak), and I don't understand why the following code does not work properly. It is just supposed to be a simple example of maintaining an open TCP connection, and sending multiple gobs through it. The code will send, and receive, but often corrupts its data.
Thank you in advance.
package main
import (
"encoding/gob"
"fmt"
"net"
"strconv"
"time"
)
type Message struct {
Msg string
}
func main() {
gob.Register(new(Message))
clientAddr, err := net.ResolveTCPAddr("tcp", "localhost:12346")
if err != nil {
fmt.Println(err)
}
serverAddr, err := net.ResolveTCPAddr("tcp", "localhost:12345")
if err != nil {
fmt.Println(err)
}
serverListener, err := net.ListenTCP("tcp", serverAddr)
if err != nil {
fmt.Println(err)
}
conn, err := net.DialTCP("tcp", clientAddr, serverAddr)
if err != nil {
fmt.Println(err)
}
serverConn, err := serverListener.AcceptTCP()
if err != nil {
fmt.Println(err)
}
done := false
go func() {
for !done {
recieveMessage(serverConn)
}
}()
for i := 1; i < 1000; i++ {
sent := Message{strconv.Itoa(i)}
sendMessage(sent, conn)
}
time.Sleep(time.Second)
done = true
}
func sendMessage(msg Message, conn *net.TCPConn) {
enc := gob.NewEncoder(conn)
err := enc.Encode(msg)
if err != nil {
fmt.Println(err)
}
}
func recieveMessage(conn *net.TCPConn) {
msg := new(Message)
dec := gob.NewDecoder(conn) // Will read from network.
err := dec.Decode(msg)
if err != nil {
fmt.Println(err)
}
fmt.Println("Client recieved:", msg.Msg)
}
The problem is that the decoder can buffer data from the next message. When this happens, the next new decoder starts in the middle of a message. The fix is to use a single encoder and decoder.
func main() {
...
dec := gob.NewDecoder(conn) // Will read from network.
enc := gob.NewEncoder(serverConn)
go func() {
for !done {
recieveMessage(dec)
}
}()
for i := 1; i < 1000; i++ {
sent := Message{strconv.Itoa(i)}
sendMessage(sent, enc)
}
...
}
func sendMessage(msg Message, enc *gob.Encoder) {
err := enc.Encode(msg)
if err != nil {
fmt.Println(err)
}
}
func recieveMessage(dec *gob.Decoder) {
msg := new(Message)
err := dec.Decode(msg)
if err != nil {
fmt.Println(err)
}
fmt.Println("Client recieved:", msg.Msg)
}
Run it in the playground

Resources