Double read from socket - sockets

Go version: go1.14.4 darwin/amd64
TCP server
package main
import (
"fmt"
"io"
"net"
"time"
)
const (
maxBufLen int = 4 * 1024
)
type Server struct {
}
func (s *Server) Start() {
listener, err := net.Listen("tcp", "localhost:9001")
if err != nil {
panic(err)
}
var connections []net.Conn
defer func() {
for _, conn := range connections {
// ignore
_ = conn.Close()
}
}()
// loop...
for {
connected, err := listener.Accept()
if err != nil {
if ne, ok := err.(net.Error); ok && ne.Temporary() {
// temporary err will bi ignored
continue
} else {
fmt.Println(err)
return
}
}
go handleConn(connected, true)
connections = append(connections, connected)
}
}
func handleConn(conn net.Conn, server bool) {
buf := make([]byte, maxBufLen)
for {
// read
setTimeout(conn)
_, err := conn.Read(buf)
if err != nil {
if ne, ok := err.(net.Error); ok && (ne.Timeout() || ne.Temporary()) {
fmt.Println("need continue...")
continue
}
if err == io.EOF {
fmt.Println("EOF")
break
}
// other...
panic(err)
}
// handle recv msg.
s := string(buf)
if server {
//fmt.Println("server recv req ", s)
} else {
fmt.Println("client recv resp ", s)
}
if server {
output := "hi " + s
ob := []byte(output)
_, err := conn.Write(ob)
if err != nil {
fmt.Println(err)
break
}
}
}
}
func setTimeout(conn net.Conn) {
setErr := conn.SetReadDeadline(time.Now().Add(20 * time.Second))
if setErr != nil {
panic(setErr)
}
}
TCP client
package main
import (
"net"
"time"
)
type Client struct {
Exit chan struct{}
}
func (c *Client) Start() {
conn, err := net.Dial("tcp", "localhost:9001")
if err != nil {
panic(err)
}
defer conn.Close()
go handleWrite(conn)
go handleConn(conn, false)
<-c.Exit
}
func handleWrite(conn net.Conn) {
for {
input := "carryxyh"
_, err := conn.Write([]byte(input))
if err != nil {
panic(err)
}
<-time.After(100 * time.Second)
}
}
Main function
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
)
type Starter interface {
Start()
}
func main() {
var s Server
var c Client
go s.Start()
go c.Start()
sigs := make(chan os.Signal)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
<-sigs
c.Exit <- struct{}{}
fmt.Println("exit")
}
Running package main will print :
client recv resp hi carryxyh
client recv resp carryxyh
Printed twice. But from the program point of view, the server only writes information to the client once, and the content of the information should be hi carryxyh. But the client printed carryxyh in addition to hi carryxyh, which made me very confused.
During the investigation, I accidentally modified a line of code, and the program immediately returned to normal:
modeifycode
As shown above, I modified the server response information: output := "hi "+ s => output := "hi ", at this time the program only prints client recv resp hi.
This makes me completely confused, can anyone help me solve this problem? It would be better if there is a troubleshooting idea.

enter image description here
这里你忽略了读取的字节长度,可能返回0字节,你又把buf的内容 又回写给client了.
_, err := conn.Read(buf) 改成 bytesRead, err := conn.Read(buf) ;
if bytesRead <= 0 { // 没有buf 可以读取 }
--
eg:
if bytesRead == 0 && err == nil {
err = io.EOF
log.Errorf("[network] ReadOnce maybe always return (0, nil) and causes dead loop, Connection = %d, Local Address = %+v, Remote Address = %+v",
c.id, c.rawConnection.LocalAddr(), c.RemoteAddr())
}

Related

Why accepted two same 5-tuple socket when concurrent connect to the server?

server.go
package main
import (
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
_ "net/http/pprof"
"sync"
"syscall"
)
type ConnSet struct {
data map[int]net.Conn
mutex sync.Mutex
}
func (m *ConnSet) Update(id int, conn net.Conn) error {
m.mutex.Lock()
defer m.mutex.Unlock()
if _, ok := m.data[id]; ok {
fmt.Printf("add: key %d existed \n", id)
return fmt.Errorf("add: key %d existed \n", id)
}
m.data[id] = conn
return nil
}
var connSet = &ConnSet{
data: make(map[int]net.Conn),
}
func main() {
setLimit()
ln, err := net.Listen("tcp", ":12345")
if err != nil {
panic(err)
}
go func() {
if err := http.ListenAndServe(":6060", nil); err != nil {
log.Fatalf("pprof failed: %v", err)
}
}()
var connections []net.Conn
defer func() {
for _, conn := range connections {
conn.Close()
}
}()
for {
conn, e := ln.Accept()
if e != nil {
if ne, ok := e.(net.Error); ok && ne.Temporary() {
log.Printf("accept temp err: %v", ne)
continue
}
log.Printf("accept err: %v", e)
return
}
port := conn.RemoteAddr().(*net.TCPAddr).Port
connSet.Update(port, conn)
go handleConn(conn)
connections = append(connections, conn)
if len(connections)%100 == 0 {
log.Printf("total number of connections: %v", len(connections))
}
}
}
func handleConn(conn net.Conn) {
io.Copy(ioutil.Discard, conn)
}
func setLimit() {
var rLimit syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {
panic(err)
}
rLimit.Cur = rLimit.Max
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {
panic(err)
}
log.Printf("set cur limit: %d", rLimit.Cur)
}
client.go
package main
import (
"bytes"
"flag"
"fmt"
"io"
"log"
"net"
"os"
"strconv"
"sync"
"syscall"
"time"
)
var portFlag = flag.Int("port", 12345, "port")
type ConnSet struct {
data map[int]net.Conn
mutex sync.Mutex
}
func (m *ConnSet) Update(id int, conn net.Conn) error {
m.mutex.Lock()
defer m.mutex.Unlock()
if _, ok := m.data[id]; ok {
fmt.Printf("add: key %d existed \n", id)
return fmt.Errorf("add: key %d existed \n", id)
}
m.data[id] = conn
return nil
}
var connSet = &ConnSet{
data: make(map[int]net.Conn),
}
func echoClient() {
addr := fmt.Sprintf("127.0.0.1:%d", *portFlag)
dialer := net.Dialer{}
conn, err := dialer.Dial("tcp", addr)
if err != nil {
fmt.Println("ERROR", err)
os.Exit(1)
}
port := conn.LocalAddr().(*net.TCPAddr).Port
connSet.Update(port, conn)
defer conn.Close()
for i := 0; i < 10; i++ {
s := fmt.Sprintf("%s", strconv.Itoa(i))
_, err := conn.Write([]byte(s))
if err != nil {
log.Println("write error: ", err)
}
b := make([]byte, 1024)
_, err = conn.Read(b)
switch err {
case nil:
if string(bytes.Trim(b, "\x00")) != s {
log.Printf("resp req not equal, req: %d, res: %s", i, string(bytes.Trim(b, "\x00")))
}
case io.EOF:
fmt.Println("eof")
break
default:
fmt.Println("ERROR", err)
break
}
}
time.Sleep(time.Hour)
if err := conn.Close(); err != nil {
log.Printf("client conn close err: %s", err)
}
}
func main() {
flag.Parse()
setLimit()
before := time.Now()
var wg sync.WaitGroup
for i := 0; i < 20000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
echoClient()
}()
}
wg.Wait()
fmt.Println(time.Now().Sub(before))
}
func setLimit() {
var rLimit syscall.Rlimit
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {
panic(err)
}
rLimit.Cur = rLimit.Max
if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit); err != nil {
panic(err)
}
log.Printf("set cur limit: %d", rLimit.Cur)
}
running command
go run server.go
---
go run client.go
server running screenshot
The client simultaneously initiates 20,000 connections to the server, and the server accepted two remotePort connections that are exactly the same (in a extremely short period of time).
I try to use tcpconn.py from bcc (patched from tcpconnect.py by add skc_num(aka: local_port))
tcpaccept.py
tracing the connection, and also finds that the remote port is duplicated on the server side when there is no duplicate on the client side
In my understanding, the 5-tuple of the socket will not be duplicated, Why the server accepted two sockets with exactly the same remote port?
My test environment:
Fedora 31, kernel version 5.3.15 x86_64
and
Ubuntu 18.04.3 LTS, kernel version 4.19.1 x86_64
go version go1.13.5 linux/amd64
wireshark:
server TCP Keep-Alive to both ACK & PSH+ACK
server TCP Keep-Alive to PSH+ACK only
Connection is added to the map data map[int]net.Conn when it is established, but when connection is closed it is not removed from the map. So if connection gets closed its port become free and could be reused by an Operation System for next connection. That's a reason why you can see duplicate ports.
Try to remove port from map when they are get closed.

How does golang's net.Conn.Read when to stop reading?

I'm trying to write a simple sockets based go server. I'm just wondering how does the connection.Read below knows when to stop reading.
(Note: this is not my code, I copied it from Unix Sockets in Go as example)
package main
import (
"log"
"net"
)
func echoServer(c net.Conn) {
for {
buf := make([]byte, 512)
nr, err := c.Read(buf)
if err != nil {
return
}
data := buf[0:nr]
println("Server got:", string(data))
_, err = c.Write(data)
if err != nil {
log.Fatal("Write: ", err)
}
}
}
func main() {
l, err := net.Listen("unix", "/tmp/echo.sock")
if err != nil {
log.Fatal("listen error:", err)
}
for {
fd, err := l.Accept()
if err != nil {
log.Fatal("accept error:", err)
}
go echoServer(fd)
}
}
Is it the EOF character or there's something else?
It would be really helpful if someone can point me to a link official go docs. Thanks.
This is the implementation of the default Read method on net.Conn.Read:
// Read implements the Conn Read method.
func (c *conn) Read(b []byte) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
}
n, err := c.fd.Read(b)
if err != nil && err != io.EOF {
err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
}
return n, err
}
This is the implementation of the c.fd.Read(b) that is called within the function above:
func (fd *netFD) Read(p []byte) (n int, err error) {
if err := fd.readLock(); err != nil {
return 0, err
}
defer fd.readUnlock()
if len(p) == 0 {
// If the caller wanted a zero byte read, return immediately
// without trying. (But after acquiring the readLock.) Otherwise
// syscall.Read returns 0, nil and eofError turns that into
// io.EOF.
// TODO(bradfitz): make it wait for readability? (Issue 15735)
return 0, nil
}
if err := fd.pd.prepareRead(); err != nil {
return 0, err
}
if fd.isStream && len(p) > 1<<30 {
p = p[:1<<30]
}
for {
n, err = syscall.Read(fd.sysfd, p)
if err != nil {
n = 0
if err == syscall.EAGAIN {
if err = fd.pd.waitRead(); err == nil {
continue
}
}
}
err = fd.eofError(n, err)
break
}
if _, ok := err.(syscall.Errno); ok {
err = os.NewSyscallError("read", err)
}
return
}
So, yes, an EOF will make it stop reading. But so will plenty of other non-nil errors.
It will stop reading when its underlying implementation hits any error.
Error may be an actual I/O error, or it could be the operating system signaling connection closed with io.EOF, or it could be a timeout, so on.

Multi writes and reads hanging - golang/net pkg

I am trying to learn Golang (and net pkg). I have written a simple client
and server. Client sends two messages in sequence and reads server msg.
Server reads two messages from a client and sends one message - this hand
shake is hanging. Could you suggest what I am missing? Thanks.
When client combine two messages into one and sends it (so the server reads
only once), this does not hang.
/* ======= Server start ==============================================*/
package main
import (
"fmt"
"net"
"os"
)
func processClients(cfd net.Conn) {
clientMsg := make([]byte, 128)
_, err := cfd.Read(clientMsg) // read client msg
if err != nil {
return
}
clientID := make([]byte, 10)
_, err = cfd.Read(clientID) // read client id
if err != nil {
return
}
clientMsg = append(clientMsg, clientID...) // TBD: handle len boundaries
fmt.Println("Server received msg:", string(clientMsg))
_, err = cfd.Write(clientMsg[0:len(clientMsg)]) // ack client msg
if err != nil {
return
}
}
func initServer() {
lfd, err := net.Listen("unix", "/tmp/unix.socket")
if err != nil {
fmt.Println("net.Listen error", err)
return
}
defer os.Remove("/tmp/unix.socket")
fmt.Println("Listening on /tmp/unix.socket")
for {
fd, err := lfd.Accept()
if err != nil {
fmt.Println("Accept() error", fd)
break
}
go processClients(fd)
}
}
func main() {
initServer()
}
/* ======= Server end ===============================================*/
/* ======= Client Start ===============================================*/
package main
import (
"fmt"
"net"
"sync"
)
var wg sync.WaitGroup
var clientID int
func sendReq() {
fd, err := net.Dial("unix", "/tmp/unix.socket")
if err != nil {
return
}
defer fd.Close()
clientID++
id := fmt.Sprintf("%v", clientID)
_, err = fd.Write([]byte(id)) //send client id
if err != nil {
return
}
_, err = fd.Write([]byte("Hello there, I am client")) // send client msg
if err != nil {
return
}
serverMsg := make([]byte, 128)
_, err = fd.Read(serverMsg) // Read server msg
if err != nil {
return
}
fmt.Println(string(serverMsg))
wg.Done()
}
func main() {
wg.Add(5)
go sendReq()
go sendReq()
go sendReq()
go sendReq()
go sendReq()
wg.Wait()
}
/* ======= Client end ===============================================*/

Match regexp email in website in go

I try to find email match in a website in goland with a file include url, for example, if i put "http://facebook.com" in the file, he will try to find all email find in the website, but he always result 0. I think I choose the wrong function but i try to find other function but i've got the same result. Here the code :
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"net/http"
"os"
"regexp"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
go emailWeb(os.Args[1], &wg)
wg.Wait()
}
func emailWeb(name string, wg *sync.WaitGroup) {
file, err := os.Open(name)
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
str := scanner.Text()
nb_arobase := numberEmail(str)
fmt.Println("URL : ", str, " nb email: ", nb_arobase)
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
(*wg).Done()
}
func numberEmail(url string) int {
count := 0
reg := regexp.MustCompile(`[a-z0-9._%+\-]+#[a-z0-9.\-]+\.[a-z]{2,4}`)
response, err := http.Get(url)
if err != nil {
log.Fatal(err)
} else {
str := response.Body
buf := new(bytes.Buffer)
buf.ReadFrom(str)
bodyStr := buf.String()
for i := 0; i < len(bodyStr); i++ {
if reg.MatchString(string(bodyStr[i])) {
count += 1
}
}
}
return count
}
You're trying to match the regexp against each individual character in the http response body. You can count the matches in the entire body if you want by counting the matched indexes.
resp, err := http.Get(url)
if err != nil {
log.Println(err)
return 0
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Println(err)
return 0
}
return len(reg.FindAllIndex(body))

Unix Sockets in Go

I'm trying to make a simple echo client and server that uses Unix sockets. In this example, the connection seems to be unidirectional. The server can receive data from the client, but it can't send the data back. If I use tcp connections instead, it works great. Does anyone know what's wrong?
Server
package main
import "net"
import "fmt"
func echoServer(c net.Conn) {
for {
buf := make([]byte, 512)
nr, err := c.Read(buf)
if err != nil {
return
}
data := buf[0:nr]
fmt.Printf("Received: %v", string(data))
_, err = c.Write(data)
if err != nil {
panic("Write: " + err.String())
}
}
}
func main() {
l, err := net.Listen("unix", "/tmp/echo.sock")
if err != nil {
println("listen error", err.String())
return
}
for {
fd, err := l.Accept()
if err != nil {
println("accept error", err.String())
return
}
go echoServer(fd)
}
}
Client
package main
import "net"
import "time"
func main() {
c,err := net.Dial("unix","", "/tmp/echo.sock")
if err != nil {
panic(err.String())
}
for {
_,err := c.Write([]byte("hi\n"))
if err != nil {
println(err.String())
}
time.Sleep(1e9)
}
}
In your example client, you don't seem to be reading the result from the server. When I add code to do that, I see the results from the server.
Also, take a look at how I used defer and break to make the reader goroutine exit.
Server
package main
import (
"log"
"net"
)
func echoServer(c net.Conn) {
for {
buf := make([]byte, 512)
nr, err := c.Read(buf)
if err != nil {
return
}
data := buf[0:nr]
println("Server got:", string(data))
_, err = c.Write(data)
if err != nil {
log.Fatal("Write: ", err)
}
}
}
func main() {
l, err := net.Listen("unix", "/tmp/echo.sock")
if err != nil {
log.Fatal("listen error:", err)
}
for {
fd, err := l.Accept()
if err != nil {
log.Fatal("accept error:", err)
}
go echoServer(fd)
}
}
Client
package main
import (
"io"
"log"
"net"
"time"
)
func reader(r io.Reader) {
buf := make([]byte, 1024)
for {
n, err := r.Read(buf[:])
if err != nil {
return
}
println("Client got:", string(buf[0:n]))
}
}
func main() {
c, err := net.Dial("unix", "/tmp/echo.sock")
if err != nil {
panic(err)
}
defer c.Close()
go reader(c)
for {
_, err := c.Write([]byte("hi"))
if err != nil {
log.Fatal("write error:", err)
break
}
time.Sleep(1e9)
}
}