SMPP - Как нужно закрыть соединение по таймауту, если клиент не отвечает в течение 10 секунд?
Использую библиотеку для работы с SMPP (https://github.com/fiorix/go-smpp) - не много дописал свой код в следующий обработчик:
// -----------------------------------------------
// handleConnection new clients.
// -----------------------------------------------
func (_srv *ServerSmpp) handleConnection(_cfg *ConfigSmpp, c *conn) {
defer c.Close()
if err := _srv.auth(_cfg, c); err != nil {
if err != io.EOF {
log.Printf("smpp_server: server auth failed: %s\n", err)
}
return
}
notify := make(chan error)
go func() {
for {
pb, err := c.Read()
if err != nil {
notify <- err
break
}
err = _srv.Handler(_srv.RemoteProvider, c, pb)
if err != nil {
fmt.Printf("%s\n", err)
notify <- err
break
}
}
}()
for {
select {
case err:= <-notify:
if io.EOF == err {
fmt.Printf("Smpp server (read): %s\n", err)
c.Close()
return
}
case <-time.After(time.Second * 10):
fmt.Printf("Client disconnected by timeout.\n")
c.Close()
return
}
}
}
Когда этот код работает, то не Важно клиент передает данные или нет - он сбрасывает подключение каждые 10 секунду, а как сделать что бы он сбрасывал подключение только когда клиент не активный ?
Ответы (1 шт):
Для решения этой задачи я использовал метод(нашел на просторах сети), данная функция проверяет если клиент не доступный то возвращает ошибку:
// -----------------------------------------------
// Check client connect or disconnected
// -----------------------------------------------
func (c *conn) CheckIsActive() error {
var sysErr error = nil
rc, err := c.rwc.(syscall.Conn).SyscallConn()
if err != nil {
return err
}
err = rc.Read(func(fd uintptr) bool {
var buf = []byte{0}
n, _, err := syscall.Recvfrom(int(fd), buf, syscall.MSG_PEEK|syscall.MSG_DONTWAIT)
switch {
case n == 0 && err == nil:
sysErr = io.EOF
case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK:
sysErr = nil
default:
sysErr = err
}
return true
})
if err != nil {
return err
}
return sysErr
}
Дальше я создал корутину, которая вызывает метод AutoRemoveDisconnectedClients() для регулярной проверки подключённых клиентов и если клиент больше двух раз возвращает ошибку то я его отключаю, если за указанное время ошибок не было то счетчик сбрасывается:
//5 - это время в секундах для вызова проверки
go srv.AutoRemoveDisconnectedClients(5)
// -----------------------------------------------
// Check client connect or disconnected (if disconnected then remove from map)
// _srv.listConnectClients -> map[string]Conn - ключ IP:PORT
// -----------------------------------------------
func (_srv *ServerSmpp) AutoRemoveDisconnectedClients(d time.Duration) {
for {
time.Sleep(d * time.Second)
for key, client := range _srv.listConnectClients {
err := client.CheckIsActive()
log.Printf("-----------------------------------------------")
if err != nil {
if client.GetNumberOfAttemptsIO() > 2 {
if err != nil {
log.Printf("Detected client %s closed LAN connection: %s", key, err)
} else {
log.Printf("Detected client %s closed LAN connection.", key)
}
err := client.Close()
if err != nil {
log.Printf("Error close client %s : %s", key, err)
}
delete(_srv.listConnectClients, key)
log.Printf("Client %s - removed from smpp server", key)
} else {
client.AddNumberOfAttemptsIO()
}
} else {
client.ResetNumberOfAttemptsIO()
}
}
}
}