Как корректно закрывать tcp соединение?

Есть некий сервис, написанный на Go, запущенный на Ubuntu 16.04.
Суть работы в том, что он опрашивает порядка 30 серверов.
После получения данных от сервера - должен в ответ послать информацию, что данные получены, в ответ на это сервер кинет еще порцию данных и так далее. Бывает так, что данные на сервере кончились, и тогда просто засыпаю на 60 секунд, затем все по-новой.
Так же бывает, что сервера не отвечают (обрыв сети или еще какие то проблема на стороне сервера (не важно)), в таких случаях закрываю соединение и пытаюсь подключиться по-новой, через определенный интервал.
Дак вот после запуска сервиса - наблюдаю следующую картину:
5c403ec5cf0a1064315090.png

Затем, через какое то время (видимо когда произошли дисконнекты):
5c4043e149a38489791413.png

Что в последствии (часов через 6) приводит к ошибке: go dial error on addr dial tcp socket: to many open files
т.е. создается socket? B соединение как бы остается в подвисшем состоянии?
Хотя соединение явно закрывается: conn.Close()

примерный код, чтобы понимать, что к чему:

//Сбор данных - вызов в гоурутине
func stantionListener(server Servers, p DataProducer)  {
	//Основной цикл для сервера
	for {
		conn, err := net.Dial("tcp", "адрес сервера")
		if err != nil {
			log.Fatal("dial error on addr:", addr, err)
			return
		}
		defer conn.Close()
		
		//Цикл, в котором происходит обмен с сервером данными
		for {
			if wr, err := conn.Write([]byte("Запрос к серверу")); //Запрос #1
				wr == 0 || err != nil {
				log.Println(addr, err)
				break
			}
			err = conn.SetReadDeadline(time.Now().Add(5 * time.Second))
			if err != nil {
				log.Println(addr, err)
				break
			}

			//Пытаемся получить данные в ответ
			buff := make([]byte, 1024)
			rd, err := conn.Read(buff)
			if err != nil{
				log.Println(addr, err)
			}

			err = res.Parser(buff[:rd])
			if err != nil {
				log.Println(err, stDesc)
			} else {
				//Отправляем запрос о том, что все ок
				if wr, err := conn.Write([]byte("ok, данные получил")); //Запрос #4
					wr == 0 || err != nil {
					log.Println(err, stDesc)
				}
			}

			d := time.Duration(kpi.current * float32(time.Second))
			time.Sleep(d)
		}//end for

		log.Println("error, when connect or receive data", stDesc, "wait 60seconds")
		time.Sleep(time.Minute) //Ждем 1 минуту, прежде чем выполнить повторное подключение
	}
}


Как я понял, при повторном подключении к тому же серверу создается вместо TYPE: IPv4 - sock, device: 0x7
  • Вопрос задан
  • 631 просмотр
Решения вопроса 1
igorzakhar
@igorzakhar
Не отрабатывает вызов:
defer conn.Close()
из-за бесконечного цикла.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@vipsiteedit
Закрывай соединение в конце первого цикла conn.Close(), так как defer выполняется только при завершении метода.
.....
      d := time.Duration(kpi.current * float32(time.Second))
      time.Sleep(d)
    }//end for
    conn.Close()
    log.Println("error, when connect or receive data", stDesc, "wait 60seconds")
    time.Sleep(time.Minute) //Ждем 1 минуту, прежде чем выполнить повторное подключение
  }
}

Или сделать отдельный метод внутри первого цикла, в котором можно использовать defer conn.Close()
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы