Клиент не может отправить данные на сервер TCP в golang? - PullRequest
0 голосов
/ 02 марта 2019

У меня есть и TCP-сервер, и клиент. Простой TCP-сервер будет просто получать входящие данные и распечатывать их, а клиент будет непрерывно создавать сокет-соединение и отправлять данные на TCP-сервер в цикле.

я получил информацию о том, что если TCP-соединение правильно закрыто, этот процесс должен продолжаться без сбоев.

Но после некоторого количества данных, полученных от клиента к серверу, клиент падает с ошибкой

total times data send: 16373

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x10d7594]

goroutine 1 [running]:
main.sendData()

/Users/apple/Desktop/Personal/umbrellaserver/src/tests/clinet.go:178 
+0xb4
main.main()

/Users/apple/Desktop/Personal/umbrellaserver/src/tests/clinet.go:170 
+0x2a
exit status 2

Server.go

package main

import (
    "bufio"
    "fmt"
    "net"
    "sync"
)

var wg sync.WaitGroup
var count = 0
var timeX string = ""

var connQueue = make(chan string)

func main() {
    tcpListner := startTCPConnection()
    incomingTCPListener(tcpListner)
}

//startTCPConnection
func startTCPConnection() net.Listener {
    tcpListner, tcpConnectonError := net.Listen("tcp", "localhost:3000")
    if tcpConnectonError != nil {
        print(tcpConnectonError)
        return 
    }
    return tcpListner
}

//incomingTCPListener
func incomingTCPListener(tcpListner net.Listener) {

    for {
        incomingConnection, incomingConnectionError := tcpListner.Accept()
        if incomingConnectionError != nil {
            print(incomingConnectionError)
            return
        }
        wg.Add(1)
        go processIncomingRequest(incomingConnection)
        wg.Wait()
    }
}

//processIncomingRequest
func processIncomingRequest(connection net.Conn) {

    defer connection.Close()

    var scanner = bufio.NewScanner(connection)

    var blob = ""
    for scanner.Scan() {
        fmt.Println("sadd")
        text := scanner.Text()
        blob += text
    }
    print(blob)
    count++
    fmt.Println("totalCount", count)
    wg.Done()
}

Client.go

package main

import (
    "fmt"
    "net"
)

var count = 0

func testJSON2() string {
    return `Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.`
}

func main() {
    for i := 0; i < 1000000; i++ {
        sendData()
    }

}

func sendData() {

    connection, connectionError := net.Dial("tcp", "localhost:3000")
    defer connection.Close()

    if connectionError != nil {
        fmt.Println(connectionError)
        return 
    }
    newmessage := testJSON2()
    connection.Write([]byte(newmessage + "\n"))
    count++
    fmt.Println(count)
}

Есть ли способ избежать этого сбоя и сделать егобегать постоянно? Я совершенно новичок в Go, поэтому, если я совершаю какую-то глупую ошибку, извините.

Ответы [ 3 ]

0 голосов
/ 10 марта 2019

package main

import (
	"bufio"
	"fmt"
	"net"
	"sync"
)

var wg sync.WaitGroup
var count = 0
var timeX string = ""

var connQueue = make(chan string)

func main() {
	tcpListner := startTCPConnection()
	incomingTCPListener(tcpListner)
    wg.Wait()
}

//startTCPConnection
func startTCPConnection() net.Listener {
	tcpListner, tcpConnectonError := net.Listen("tcp", "localhost:3000")
	if tcpConnectonError != nil {
		print(tcpConnectonError)
        // return 
        log.Fatal(tcpConnectonError)
	}
	return tcpListner
}

//incomingTCPListener
func incomingTCPListener(tcpListner net.Listener) {

	for {
		incomingConnection, incomingConnectionError := tcpListner.Accept()
		if incomingConnectionError != nil {
			print(incomingConnectionError)
            return
		}
		wg.Add(1)
		go processIncomingRequest(incomingConnection)
		// wg.Wait()
	}
}

//processIncomingRequest
func processIncomingRequest(connection net.Conn) {

	defer connection.Close()

	var scanner = bufio.NewScanner(connection)

	var blob = ""
	for scanner.Scan() {
		fmt.Println("sadd")
		text := scanner.Text()
		blob += text
	}
	print(blob)
	count++
	fmt.Println("totalCount", count)
	wg.Done()
}

Проблема в server.go.Я предполагаю, что вы исчерпали порты, вызвав wg.Wait () внутри входящей функции TCPListener () вместо main ().Также пустое возвращение в функции startTCPConnection () приведет к ошибке компиляции.

0 голосов
/ 12 марта 2019

Во-первых, я бы порекомендовал, если вы хотите печатать в stderr (т. Е. Ваши вызовы на печать), используйте библиотеку fmt

fmt.Fprintln(os.Stderr, "hello world")

Почему: потому что функция печати не гарантированно останется на языке. 1


Во-вторых, общепринятая практика - давать имена ошибок так же, как err, вам не нужно указывать ошибки, такие как tcpConnectionError.


В-третьих, поскольку вы используете tcp в connection, connectionError := net.Dial("tcp", "localhost:3000"), сервер прослушивает ipv6 и ipv4.Я наблюдал, по крайней мере, на машинах Windows, соединение открывает два соединения, одно для ipv4 и ipv6, а затем отбрасывает соединение ipv6 в пользу ipv4.


Наконец, когда TCP-соединения закрываются, порт не может бытьсразу же после этого используется повторно, поскольку операционная система должна ожидать длительность интервала TIME_WAIT (максимальное время жизни сегмента, MSL).
Ваш клиентский код открывает огромное количество tcp-соединений, которые очень недолговечны и зависят от диапазонаиз вашего диапазона портов, ваш код может или не может произойти сбой.Судя по сумме 16373, у вас есть диапазон по умолчанию. 2

>> sysctl net.inet.ip.portrange.first net.inet.ip.portrange.last
net.inet.ip.portrange.first: 49152
net.inet.ip.portrange.last: 65535

Наконец,

Если вы хотите избежать сбоев из-за нехватки портов:
1. Увеличьте эфемерный диапазон портов
2. Используйте Docker, контейнеры находятся в собственной сети, следовательно, используют другой набор портов, минуя ограниченный диапазон портов.
3. Внесите тикер в код своего клиента, чтобы симулировать соединение каждые x секунд/ минуты

package main

import (
    "fmt"
    "net"
    "time"
)

var count = 0

func testJSON2() string {
    return `Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum comes from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", comes from a line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, accompanied by English versions from the 1914 translation by H. Rackham.`
}

func main() {
    max := 1000

    timer1 := time.NewTicker(5 * time.Second)

    i := 0
    for range timer1.C {
        sendData()
        if i == max {
            timer1.Stop()
        }
        i++
    }
}

func sendData() {

    connection, connectionError := net.Dial("tcp", "localhost:3000")
    fmt.Println(connection.LocalAddr())

    if connectionError != nil {
        fmt.Println(connectionError)
        return
    }
    newmessage := testJSON2()
    connection.Write([]byte(newmessage + "\n"))
    count++
    fmt.Println(count)

    err := connection.Close()
    if err != nil {
        fmt.Println(err)
    }
}

Ссылки
^ 1: https://tip.golang.org/pkg/builtin/#print
^ 2: Каков диапазон временных портов на Mac?
^ 3: https://www.fromdual.com/huge-amount-of-time-wait-connections

0 голосов
/ 03 марта 2019
if connectionError != nil {
        fmt.Println(connectionError)
        return 
    }
defer connection.Close()

defer connection.Close () должно быть после проверки на ошибку, поскольку переменная соединения может быть nil, если набор номера возвращается с некоторой ошибкой.

...