I have a simple UDP struct I made in Go, and when I run the following code, it blocks forever. For reference, the address of my server is running on the same computer running the client, but the server listens on a different port and address than the one that is bound to by the client.
var client Clientee
client.Create("the address of my server")
err, messages := client.Read() // <-- HERE IT BLOCKS FOREVER
if err != nil { panic(err) }
fmt.Printf("Messages: %s", messages)
Here's the part of the code that declares my struct:
package controllers
import (
"fmt"
"net"
"time"
)
const (
BUF_SIZE = 1024
CLIENT_PORT = "4097"
SERVER_PORT = "4096"
)
type Clientee struct {
ClServerAddr *net.UDPAddr
ClLocalAddr *net.UDPAddr
ClConn *net.UDPConn
ClWasShutdown bool
}
// Initialize and connect the Clientee
func (c *Clientee) Create(hostAddr string) error {
var err error
c.ClWasShutdown=false
// Resolve the server's address
c.ClServerAddr, err = net.ResolveUDPAddr("udp", hostAddr+":"+SERVER_PORT)
if err != nil { return err }
fmt.Println("Server addr = ",c.ClServerAddr.String())
// Resolve our local address
c.ClLocalAddr, err = net.ResolveUDPAddr("udp", ":"+CLIENT_PORT)
if err != nil { return err }
// Create the connection
c.ClConn, err = net.ListenUDP("udp", c.ClLocalAddr)
if err != nil { return err }
// Pause
time.Sleep(time.Millisecond*200)
return nil
}
// Send a message to the Server
func (c *Clientee) Send(msg string) error {
_, err := c.ClConn.WriteToUDP([]byte(msg), c.ClServerAddr)
if err!=nil { return err }
return nil
}
// Read messages from the Server
func (c *Clientee) Read() (error, string) {
bfr:=make([]byte, BUF_SIZE) // Make the buffer
n, addr, err := c.ClConn.ReadFromUDP(bfr)
if err!=nil { return err, "" }
// If the message doesn't come from the server, don't return it
if addr.String()!=c.ClServerAddr.String() {
return nil, ""
}
return nil, string(bfr[0:n])
}
// Close the Connection.
func (c *Clientee) Close() error {
return c.ClConn.Close()
}
ReadFromUDP will block until something is received. The docs refer you to ReadFrom which says "ReadFrom implements the PacketConn ReadFrom method.". Looking at the PacketConn docs you will find the following:
ReadFrom reads a packet from the connection, copying the payload into
p. It returns the number of bytes copied into p and the return address
that was on the packet. It returns the number of bytes read (0 <= n <=
len(p)) and any error encountered. Callers should always process the n > 0
bytes returned before considering the error err.
ReadFrom can be made to time out and return an Error with Timeout() == true after a
fixed time limit; see SetDeadline and SetReadDeadline.
So if you do not want this to block (as per the comments) then you can either:
Use SetDeadline or SetReadDeadline to set a deadline.
Run ReadFromUDP within a goroutine and handle data as it's received (which may include putting received data onto a channel)
Note: Calling ReadFromUDP with a zero length buffer may not block but this depends upon the operating system implementation so is probably not something to rely on.
Related
I am having an issue with instability when using gob for TCP communication.
The main problem is that if i transfer data "to fast" i either get errors where the server terminates the connection or the package simply doesn't arrive at the server. Now, if i add a delay of 20ms between packages, everything runs as expected.
Sadly i cannot link this to playground as i am running it in three different libraries, but i have inserted the essential/culprit code.
My guess is that if i don't have a delay timer i am overwriting the stream. Any ideas?
Update: By swapping out the receiver to bufio.NewReader(c.socket) i am actually able to get an error: "gob: unknown type id or corrupted data" which somewhat like the same issue as https://github.com/golang/go/issues/1238#event-242248991
//client -> server, running as a goroutine
func (c *Client) transmitter() {
d := 20 * time.Millisecond
timer := time.NewTimer(d) //silly hack
for {
select {
case gd := <- c.broadcast:
<- timer.C
Write(c.socket, gd.Data, gd.NetworkDataType)
timer.Reset(d) //refreshing timer
}
}
}
//server <- client, running as a goroutine
func (c *client) receiver (s *Server){
for {
in, err := Read(c.socket)
if err != nil {
log.println(err)
}
//doing stuff
}
}
func Read(conn net.Conn) (GeneralData, error) {
in := GeneralData{}
if err := gob.NewDecoder(conn).Decode(&in); err != nil {
return in, err
}
return in, nil
}
func Write(conn net.Conn, data interface{}, ndt NetworkDataType) {
err := gob.NewEncoder(conn).Encode(GeneralData{ndt,data})
if err != nil {
log.Println("error in write: ", err)
}
}
Problem: structure's field is not replaced with fresh value if it is zero after an rpc call.
Here is minimal code sample:
package main
import (
"fmt"
"log"
"net"
"net/rpc"
)
type RpcObject int
type Reply struct {
A int
}
func (*RpcObject) GetSlice(req int, reply *[]Reply) error {
*reply = []Reply{{0}, {158}}
return nil
}
func Serve() {
addr, err := net.ResolveTCPAddr("tcp", "0.0.0.0:12345")
if err != nil {
log.Fatal(err)
}
inbound, err := net.ListenTCP("tcp", addr)
if err != nil {
log.Fatal(err)
}
handler := new(RpcObject)
rpc.Register(handler)
rpc.Accept(inbound)
}
func main() {
go Serve()
var err error
var client *rpc.Client
for client, err = rpc.Dial("tcp", "localhost:12345"); err != nil; client, err = rpc.Dial("tcp", "localhost:12345") {
fmt.Println("connecting...")
}
reply := []Reply{{225}, {9946}}
client.Call("RpcObject.GetSlice", 0, &reply)
fmt.Println(reply)
}
Output:
[{225} {158}]
I assume it is a problem with gob format, however I am not sure. Does someone know how to fix this?
The application produced the expected results. The gob encoder does not transmit the first element in the reply slice because the element is the zero value. The decoder does not set the first element in main's reply slice because a value was not received for that element.
Decode to a zero value if you do not want to set defaults for values missing from the reply:
...
var reply []Reply
client.Call("RpcObject.GetSlice", 0, &reply)
...
I do have a process receiving data from second local process. I need to test if connection errors are handled well AND if it automatically reconnects and keep receiving data after a disconnection.
To do so I am trying to make it disconnect abruptly or put the TCP connection in an error state from a unit test.
As seen in this question to check if a connection is closed I am checking for data to come and test if it returns an error.
I am not sure how to:
close the connection ungracefully
make it be in an error state
This is the essence of my data receiver:
import (
"bufio"
"encoding/json"
"fmt"
"io"
"net"
)
type Message struct {
ID string `json:"id"`
}
func ReceiveData(listener Listener) {
var tcpConn net.Conn
var addr string = "127.0.0.1:9999"
tcpConn, err := net.Dial("tcp", addr)
socketReader := bufio.NewReader(tcpConn)
decoder := json.NewDecoder(socketReader)
for {
var msg Message
if err := decoder.Decode(&msg); err == io.EOF {
listener.ProcessUpdate(Message{}, fmt.Errorf("Received EOF"), nil)
tcpConn = nil
return
} else if err != nil {
listener.ProcessUpdate(Message{}, nil, fmt.Errorf("Error decoding message: %s", err.Error()))
tcpConn = nil
return
}
// process message
_ = msg
// Test disconnection
// This does not disconnect:
// tcpConn = nil
// This does but gracefully:
// tcpConn.Close()
}
I am not mocking the TCP connection as I'd like to try with the real data producer. If is needed I'll look at it.
A solution is to set a deadline to the TCP connection itself:
tcpConn.SetDeadline(time.Now())
Later this will trigger a timeout error which can be caught with:
err := decoder.Decode(&msg);
if err != nil {
if neterr, ok := err.(net.Error); ok && neterr.Timeout() {
fmt.Errorf("TCP timeout : %s", err.Error())
} else {
fmt.Errorf("Received error decoding message: %s", err.Error())
}
}
I am experimenting with Go - and would like to create a TCP server which I can telnet to, send commands and receive responses.
const (
CONN_HOST = "localhost"
CONN_PORT = "3333"
CONN_TYPE = "tcp"
)
func main() {
listener, err := net.Listen(CONN_TYPE, fmt.Sprintf("%s:%s", CONN_HOST, CONN_PORT))
if err != nil {
log.Panicln(err)
}
defer listener.Close()
for {
conn, err := listener.Accept()
if err != nil {
log.Panicln(err)
}
go handleRequest(conn)
}
}
func handleRequest(conn net.Conn) {
buffer := make([]byte, 1024)
length, err := conn.Read(buffer)
if err != nil {
log.Panicln(err)
}
str := string(buffer[:length])
fmt.Println(conn.RemoteAddr().String())
fmt.Printf("Received command %d\t:%s\n", length, str)
switch str {
case "PING\r\n":
sendResponse("PONG", conn)
case "PUSH\r\n":
sendResponse("GOT PUSH", conn)
default:
conn.Write([]byte(fmt.Sprintf("UNKNOWN_COMMAND: %s\n", str)))
}
conn.Close() // closes the connection
}
func sendResponse(res string, conn net.Conn) {
conn.Write([]byte(res+"\n"))
}
The above snippet will close the connection every time, kicking me out of the terminal session. But what I actually want, is to be able to keep the connection open for more I/O operations. If I simply remove the conn.Close(), then the server appears to hang somewhere as it does not get any more responses.
The way I have resolved this is to have my handleRequest method endlessly loop so that it never exits till it receives a QUIT\r\n message. Is this appropriate - or is there a better way of achieving?
func handleRequest(conn net.Conn) {
for {
log.Println("Handling Request")
buffer := make([]byte, 1024)
length, err := conn.Read(buffer)
if err != nil {
log.Panicln(err)
}
str := string(buffer[:length])
fmt.Println(conn.RemoteAddr().String())
fmt.Printf("Received command %d\t:%s\n", length, str)
switch str {
case "PING\r\n":
sendResponse("PONG", conn)
case "PUSH\r\n":
sendResponse("GOT PUSH", conn)
case "QUIT\r\n":
sendResponse("Goodbye", conn)
conn.Close()
default:
conn.Write([]byte(fmt.Sprintf("UNKNOWN_COMMAND: %s\n", str)))
}
}
}
Your second example with the loop is already what you want. You simply loop and read as long as you want (or probably until some read/write timeout or an external cancellation signal).
However it still has an error in it:
TCP gives you a stream of bytes, where it is not guaranteed that one write from a side will yield exactly one read on the other side with the same data length. This means if the client writes PING\r\n you could still receive only PI in the first read. You could fix that by using a bufio.Scanner and always read up to the first newline.
Not sure if this is what you're looking for. Taken from net/http implementation, wrapping your net.TCPListener's Accept method.
tcpKeepAliveListener{listener.(*net.TCPListener)}
type tcpKeepAliveListener struct {
*net.TCPListener
}
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
tc, err := ln.AcceptTCP()
if err != nil {
return
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
return tc, nil
}
Refer : Link 1 & Link 2
I'm working on a websocket server and for some reason it outputs:
"WSARecv tcp 127.0.0.1:8080: Use of closed network connection."
I don't know why it says that because I haven't closed the connection at any point in time.
Below are some source code files of the server. If needed, the full source code is here on GitHub.
connection.go
package net
import (
"log"
"golang.org/x/net/websocket"
pnet "kekocity/misc/packet"
"kekocity/interfaces"
)
type Connection struct {
socket *websocket.Conn
txChan chan pnet.INetMessageWriter
rxChan chan pnet.INetMessageReader
user interfaces.IUser
}
func NewConnection(_socket *websocket.Conn) *Connection {
// The pointer allow us to modify connection struct from outside
connection := &Connection{
socket: _socket,
txChan: make(chan pnet.INetMessageWriter),
rxChan: make(chan pnet.INetMessageReader),
}
go connection.ReceivePoller()
go connection.SendPoller()
return connection
}
func (c *Connection) AssignToUser(_user interfaces.IUser) {
if _user == nil {
panic("net.connection: the user interface can not be nil!")
return
}
c.user = _user
_user.SetNetworkChans(c.rxChan, c.txChan)
}
/*
* ReceivePoller and SendPoller starts listening when the first packet is verified and the new connection is started
*/
func (c *Connection) ReceivePoller() {
for {
packet := pnet.NewPacket()
var buffer []uint8
err := websocket.Message.Receive(c.socket, &buffer)
if err == nil {
copy(packet.Buffer[0:len(buffer)], buffer[0:len(buffer)])
c.parsePacket(packet)
} else {
println(err.Error())
break
}
}
}
func (c *Connection) SendPoller() {
for {
// Read messages from transmit channel
message := <-c.txChan
if message == nil {
log.Println("SenPoller", "The message is nil, break the loop")
break
}
// Convert netmessage to packet
packet := message.WritePacket()
packet.SetHeader()
// Create byte buffer
buffer := packet.GetBuffer()
data := buffer[0:packet.GetMsgSize()]
// Send bytes off to the internetz
websocket.Message.Send(c.socket, data)
}
}
func (c *Connection) parsePacket(_packet pnet.IPacket) {
log.Println("net.connection:", "Received new packet!")
}
func (c *Connection) Close() {
// Close channels
close(c.txChan)
close(c.rxChan)
// Close the socket
c.socket.Close()
c.user = nil
}
server.go
package net
// <imports>
import (
"log"
"fmt"
"net/http"
"golang.org/x/net/websocket"
pnet "kekocity/misc/packet"
cmap "kekocity/misc/concurrentmap"
"kekocity/data/helpers"
"kekocity/net/message"
)
var server *Server
type Server struct {
port int
connectedUsers *cmap.ConcurrentMap
}
func init() {
server = newServer()
}
func newServer() *Server {
return &Server{
port: 8080,
connectedUsers: cmap.New(),
}
}
func Listen(_port int) {
server.port = _port
log.Printf("Listening for connections on port %d!", _port)
http.Handle("/ws", websocket.Handler(clientConnection))
err := http.ListenAndServe(fmt.Sprintf(":%d", _port), nil)
if err != nil {
panic("ListenAndServe: " + err.Error())
}
}
func clientConnection(clientsock *websocket.Conn) {
packet := pnet.NewPacket()
buffer := make([]uint8, pnet.PACKET_MAXSIZE)
recv, err := clientsock.Read(buffer)
if err == nil {
copy(packet.Buffer[0:recv], buffer[0:recv])
parseFirstMessage(clientsock, packet)
} else {
if err.Error() != "EOF" {
log.Println("net.server", "Client connection error:", err.Error())
}
}
}
func parseFirstMessage(_conn *websocket.Conn, _packet *pnet.Packet) {
_message := _packet.ToString()
// If the first packet length is < 1 close the socket
if len(_message) < 1 {
_conn.Close()
return
}
// Create the connection
connection := NewConnection(_conn)
// Authentication wrapper
authPacket := &message.AuthMessage{}
user, err := helpers.AuthHelper.AuthenticateUsingCredentials(_message)
if err != nil {
log.Fatal("Invalid credentials!")
authPacket.Status = "error"
} else {
// Need to check if its already logged
authPacket.Status = "success"
connection.AssignToUser(user)
connection.txChan <- authPacket
return
}
// Send bad auth message and close
connection.txChan <- authPacket
connection.Close()
}
Full source code: github
The context in the request is canceled right after the handler finishes.
serverHandler{c.server}.ServeHTTP(w, w.req)
w.cancelCtx()
This is the reason why your context. In this diagram, you can find how the context is created in the server.Serve method.
It is described in more detail in the blog post: HTTP context livetime.
In the websocket, the situation is very similar. The context is closed just after the handler finishes.
func (s Server) serveWebSocket(w http.ResponseWriter, req *http.Request) {
rwc, buf, err := w.(http.Hijacker).Hijack()
if err != nil {
panic("Hijack failed: " + err.Error())
}
// The server should abort the WebSocket connection if it finds
// the client did not send a handshake that matches with protocol
// specification.
defer rwc.Close() // <- here! It's executed when the s.Handler(conn) exites
conn, err := newServerConn(rwc, buf, req, &s.Config, s.Handshake)
if err != nil {
return
}
if conn == nil {
panic("unexpected nil conn")
}
s.Handler(conn)
}
To fix that, you can create a new context from context.Background(), add some timeouts if needed and use it instead.