Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

многопоточный сервер - отлов отключения клиента

245
12 января 2010 года
~ArchimeD~
1.4K / / 24.07.2006
Есть tcp-сервер. Многопоточный, с++, использует posix-threads, на каждого клиента - по потоку. В каждом потоке создается сокет, через который и ведется обмен данными с клиентом. Каким образом можно определить, какой именно клиент отключился?
Запись в сокет ведется следующим образом:
 
Код:
send (descriptor, buf, len, MSG_NOSIGNAL)

Вот, что пишет мануал про последний параметр:
Цитата:
MSG_NOSIGNAL
Требует не посылать сигнал SIGPIPE когда при работе с потоко-ориентированным сокетом другая сторона обрывает
соединение. Код ошибки EPIPE возвращается в любом случае.


Т.е., если клиент отключен, и произвести запись в сокет, EPIPE будет записана в errno. Насколько я понимаю, errno - глобальная переменная, и определить, какому именно потоку принадлежит ошибка, нет возможности.
Если не использовать флаг MSG_NOSIGNAL, программе будет посылаться сигнал SIGPIPE, обработчик которого опять же, будет работать не в контексте потока.

Если решать задачу в лоб, то можно вызывать send под мутексом, под мутексом же читать errno в случае, если send вернул -1, но тогда имхо, теряется весь смысл многопоточности.

Какие есть пути решения?

502
12 января 2010 года
Jail
550 / / 30.01.2007
Смотри manpage setsockopt() и обрати особое внимание на so_keepalive и tcp_keepalive или tcp_keepidle опции.
Или вот:
Код:
tcp_disconnect.py
Echo network data test program in python. This program easily translates to C & Java.

By TCP rules, the only way for a server program to know if a client has disconnected,
is to try to read from the socket. Specifically, if select() says there is data, but
recv() returns 0 bytes of data, then this implies the client has disconnected.

But a server program might want to confirm that a tcp client is still connected without
reading data. For example, before it performs some task or sends data to the client.
This program will demonstrate how to detect a TCP client disconnect without reading data.

The method to do this:
1) select on socket as poll (no wait)
2) if no recv data waiting, then client still connected
3) if recv data waiting, the read one char using PEEK flag
4) if PEEK data len=0, then client has disconnected, otherwise its connected.
Note, the peek flag will read data without removing it from tcp queue.

To see it in action: 0) run this program on one computer 1) from another computer,
connect via telnet port 12345, 2) type a line of data 3) wait to see it echo,
4) type another line, 5) disconnect quickly, 6) watch the program will detect the
disconnect and exit.

"""

import socket
import time
import select

HOST = ''       # all local interfaces
PORT = 12345    # port to listen

# listen for new TCP connections
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)
# accept new conneciton
conn, addr = s.accept()
print 'Connected by', addr
# loop reading/echoing, until client disconnects
try:
    conn.send("Send me data, and I will echo it back after a short delay.\n")
    while 1:
        data = conn.recv(1024)                          # recv all data queued
        if not data: break                              # client disconnected
        time.sleep(3)                                   # simulate time consuming work
        # below will detect if client disconnects during sleep
        r, w, e = select.select([conn], [], [], 0)      # more data waiting?
        print "select: r=%s w=%s e=%s" % (r,w,e)        # debug output to command line
        if r:                                           # yes, data avail to read.
            t = conn.recv(1024, socket.MSG_PEEK)        # read without remove from queue
            print "peek: len=%d, data=%s" % (len(t),t)  # debug output
            if len(t)==0:                               # length of data peeked 0?
                print "Client disconnected."            # client disconnected
                break                                   # quit program
        conn.send("-->"+data)                           # echo only if still connected
finally:
    conn.close()
Ну или юзать XmlBlasterConnectionUnparsed
245
21 января 2010 года
~ArchimeD~
1.4K / / 24.07.2006
Таки в экспериментальном оказалось, что errno обрабатывается отдельно для каждого потока, соответственно, получив в ответ на send -1, не проблема однозначно выяснить чем вызвана ошибка.
За пинок в нужном направлении спасибо товарищу одиссею.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог