Уведомления

Группа в Telegram: @pythonsu

#1 Июнь 10, 2010 13:29:42

yurtaev
От:
Зарегистрирован: 2009-11-17
Сообщения: 32
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

Есть class в котором создается клиент с подключением к серверу, но при создание клиентов в нитях, первый клиент создается удачно и подключается к серверу, а все последующие падают с ошибкой:

    self.s.connect((self.HOST, self.PORT))
File "<string>", line 1, in connect
error: [Errno 10056]
Errno 10056 — это ошибка «Socket is already connected», т.е ругается на то что сокет уже используется. Хотелось бы услышать ваши мнение. Заранее благодарен.



Офлайн

#2 Июнь 10, 2010 13:59:35

Alex2ndr
От:
Зарегистрирован: 2009-12-26
Сообщения: 204
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

Я понимаю ситуацию так: каждое tcp соединение идентифицируется парой сокетов - локальным и удаленных. А сокет в свою очередь является парой ip-адрес:порт. Таким образом получаем идентификатор соединения:
IP_локальный:Port_локальный - IP_удаленный:Port_удаленный

Дальнейшие рассуждения такие - если есть ошибка «Socket is already connected», то значит вы пытаетесь создать НЕ УНИКАЛЬНОЕ tcp соединение. Т е с одной и той же машины, с одного и того же порта на один и тот же адрес и порт удаленной машины пытаетесь пробросить еще один коннешен. Вот он и ругается.



Отредактировано (Июнь 10, 2010 14:00:50)

Офлайн

#3 Июнь 10, 2010 14:04:41

yurtaev
От:
Зарегистрирован: 2009-11-17
Сообщения: 32
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

Alex2ndr
Я понимаю ситуацию так: каждое tcp соединение идентифицируется парой сокетов - локальным и удаленных. А сокет в свою очередь является парой ip-адрес:порт. Таким образом получаем идентификатор соединения:
IP_локальный:Port_локальный - IP_удаленный:Port_удаленный

Дальнейшие рассуждения такие - если есть ошибка «Socket is already connected», то значит вы пытаетесь создать НЕ УНИКАЛЬНОЕ tcp соединение. Т е с одной и той же машины, с одного и того же порта на один и тот же адрес и порт удаленной машины пытаетесь пробросить еще один коннешен. Вот он и ругается.
Я тоже так подумал сначала, но если запустить программу допустим в 3-х экземплярах, то будет создано 3 удачных соединения, которые я вижу на сервере.



Офлайн

#4 Июнь 10, 2010 14:07:00

Alex2ndr
От:
Зарегистрирован: 2009-12-26
Сообщения: 204
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

Раз вы их видите, так посмотрите какие именно у них пары сокетов. Возможно что каждый экземпляр запускаясь выбирает свой случайный исходящий порт. Это достаточно просто проверить.



Отредактировано (Июнь 10, 2010 14:07:21)

Офлайн

#5 Июнь 10, 2010 14:23:32

yurtaev
От:
Зарегистрирован: 2009-11-17
Сообщения: 32
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

Alex2ndr, Ну это логично что они при соединение открывают разные локальные порты. Вопрос в том почему возникает конфликт, и почему в трэдах происходит соединение через один и тот же порт. В идеале это должно решаться автоматически. Например тут http://keysolutions.ru/articles/osnovy-raboty-s-potokami-v-python в примере создания клиента в потоках не чего лишнего не указывается, и пример работает как надо. Пока копаю в документаций по сокетам, но не чего пока не нашёл.



Офлайн

#6 Июнь 10, 2010 14:59:37

Alex2ndr
От:
Зарегистрирован: 2009-12-26
Сообщения: 204
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

А вы для каждого соединения создаете уникальный сокет(т е вызываете socket.socket() ), или используете один и тот же? (меня self.s.connect насторожило). Дальнейшие советы будут зависеть от вашего кода. Выделите ваш сбойный код в пример , показывающий такое поведение и приведите здесь.



Офлайн

#7 Июнь 10, 2010 15:24:30

yurtaev
От:
Зарегистрирован: 2009-11-17
Сообщения: 32
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

Alex2ndr
А вы для каждого соединения создаете уникальный сокет(т е вызываете socket.socket() ), или используете один и тот же? (меня self.s.connect насторожило). Дальнейшие советы будут зависеть от вашего кода. Выделите ваш сбойный код в пример , показывающий такое поведение и приведите здесь.
import socket
import threading
import time

#**************

class client(threading.Thread):

HOST = "127.0.0.1"
PORT = 411
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def connect(self):
self.s.connect((self.HOST, self.PORT))
return

def run(self):
self.connect()
while 1:
self.dispatch(self.getsocketdata(self.s))
return

#дальше идут функиций работы с данными

def getsocketdata(self, somesocket):
#**************

def dispatch(self, message):
#**************

client().start()
time.sleep(2)
client().start()



Офлайн

#8 Июнь 10, 2010 15:57:37

Alex2ndr
От:
Зарегистрирован: 2009-12-26
Сообщения: 204
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

А оно работает? Что-то сомнительно…
Как я могу чем-то помочь, если не могу воспроизвести ваш глюк. Я конечно допишу то, что не достает, но не факт, что оно будет так же как у вас. Вы сделайте минимальный РАБОЧИЙ пример. Т е чтобы запустив его я получил такую же ошибку как у вас. Кстати, если используете самописный сервер, то его тоже приведите(в минимальном виде).

Из того что пока увидел. Вы создаете один общий сокет на класс. Затем экземпляр одного и того же класса вызываете 2 раза. Вызывайте разные экземпляры или создавайте новый сокет каждый раз при соединении.



Отредактировано (Июнь 10, 2010 15:59:34)

Офлайн

#9 Июнь 10, 2010 16:28:28

yurtaev
От:
Зарегистрирован: 2009-11-17
Сообщения: 32
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

Alex2ndr
А оно работает? Что-то сомнительно…
Как я могу чем-то помочь, если не могу воспроизвести ваш глюк. Я конечно допишу то, что не достает, но не факт, что оно будет так же как у вас. Вы сделайте минимальный РАБОЧИЙ пример. Т е чтобы запустив его я получил такую же ошибку как у вас. Кстати, если используете самописный сервер, то его тоже приведите(в минимальном виде).

Из того что пока увидел. Вы создаете один общий сокет на класс. Затем экземпляр одного и того же класса вызываете 2 раза. Вызывайте разные экземпляры или создавайте новый сокет каждый раз при соединении.
Код что я привел воспроизводит ошибку ту самую, коненчо нужно запустить такой вариант:
import socket
import threading
import time

class client(threading.Thread):

HOST = "91.144.171.226"
PORT = 411
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def connect(self):
self.s.connect((self.HOST, self.PORT))
print "connect true"
return

def run(self):
self.connect()
return
print "thread 1"
client().start()
time.sleep(2)
print "thread 2"
client().start()
Клиент для работы с хабами DC++, указал адрес своего хаба для теста. Ошибка воспроизводиться, первый трэд подключается успешно, а второй падает с конфликтом. Могу конечно и весь код показать, но и на данном примере ошибка воспроизводится.



Офлайн

#10 Июнь 10, 2010 21:22:32

Alex2ndr
От:
Зарегистрирован: 2009-12-26
Сообщения: 204
Репутация: +  0  -
Профиль   Отправить e-mail  

Конфликт socket в threading

Интересная задачка
Попробовал ваш пример, только немного переделал под себя. Зачем стучаться к вашему серверу, если все равно ничего не слать. Стучусь к домашнему веб серверу:

#!/usr/bin/env python
# -*-coding: utf-8 -*-
# vim: sw=4 ts=4 expandtab ai
# pylint: disable-msg=C0301

import socket
import threading
import time

class client(threading.Thread):

HOST = "192.168.0.1"
PORT = 80
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def connect(self):
self.s.connect((self.HOST, self.PORT))
print "connect true"
return

def run(self):
self.connect()
return
print "thread 1"
c1 = client()
c1.start()
time.sleep(30)
print "thread 2"
c2 = client()
c2.start()
Тоже выдает ошибку, только немного другую:
 alex@kubu-book:~/development/PYTHON_projects$ python ~/socks_th0.py 
thread 1
connect true
thread 2
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python2.6/threading.py", line 532, in __bootstrap_inner
self.run()
File "/home/alex/socks_th0.py", line 22, in run
self.connect()
File "/home/alex/socks_th0.py", line 17, in connect
self.s.connect((self.HOST, self.PORT))
File "<string>", line 1, in connect
error: [Errno 106] Transport endpoint is already connected
В сети в это время происходит вот что:
 alex@kubu-book:~/development/PYTHON_projects$ sudo tcpdump -n host 192.168.0.1 and tcp and port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
22:08:41.155830 IP 192.168.0.5.51828 > 192.168.0.1.80: Flags [S], seq 1150385388, win 5840, options [mss 1460,sackOK,TS val 203898 ecr 0,nop,wscale 6], length 0
22:08:41.156080 IP 192.168.0.1.80 > 192.168.0.5.51828: Flags [S.], seq 2554555935, ack 1150385389, win 5792, options [mss 1460,sackOK,TS val 151545188 ecr 203898,nop,wscale 5], length 0
22:08:41.156125 IP 192.168.0.5.51828 > 192.168.0.1.80: Flags [.], ack 1, win 92, options [nop,nop,TS val 203898 ecr 151545188], length 0
22:08:44.153486 IP 192.168.0.1.80 > 192.168.0.5.51828: Flags [S.], seq 2554555935, ack 1150385389, win 5792, options [mss 1460,sackOK,TS val 151545938 ecr 203898,nop,wscale 5], length 0
22:08:44.153536 IP 192.168.0.5.51828 > 192.168.0.1.80: Flags [.], ack 1, win 92, options [nop,nop,TS val 204647 ecr 151545938,nop,nop,sack 1 {0:1}], length 0
22:08:50.153830 IP 192.168.0.1.80 > 192.168.0.5.51828: Flags [S.], seq 2554555935, ack 1150385389, win 5792, options [mss 1460,sackOK,TS val 151547438 ecr 204647,nop,wscale 5], length 0
22:08:50.153879 IP 192.168.0.5.51828 > 192.168.0.1.80: Flags [.], ack 1, win 92, options [nop,nop,TS val 206147 ecr 151547438,nop,nop,sack 1 {0:1}], length 0
22:09:02.354540 IP 192.168.0.1.80 > 192.168.0.5.51828: Flags [S.], seq 2554555935, ack 1150385389, win 5792, options [mss 1460,sackOK,TS val 151550488 ecr 206147,nop,wscale 5], length 0
22:09:02.354591 IP 192.168.0.5.51828 > 192.168.0.1.80: Flags [.], ack 1, win 92, options [nop,nop,TS val 209198 ecr 151550488,nop,nop,sack 1 {0:1}], length 0
22:09:11.194953 IP 192.168.0.5.51828 > 192.168.0.1.80: Flags [F.], seq 1, ack 1, win 92, options [nop,nop,TS val 211408 ecr 151550488], length 0
22:09:11.195511 IP 192.168.0.1.80 > 192.168.0.5.51828: Flags [F.], seq 1, ack 2, win 181, options [nop,nop,TS val 151552698 ecr 211408], length 0
22:09:11.195558 IP 192.168.0.5.51828 > 192.168.0.1.80: Flags [.], ack 2, win 92, options [nop,nop,TS val 211408 ecr 151552698], length 0
^C
12 packets captured
12 packets received by filter
0 packets dropped by kernel
т е как я и предполагал второй сокет выходит с того же самого порта, что и первый - это и порождает такую ошибку. Причем серверу на той стороне это тоже как-то не нравится(я в wireshark покопался в пакетах)

Немного переделал код -
#!/usr/bin/env python
# -*-coding: utf-8 -*-
# vim: sw=4 ts=4 expandtab ai
# pylint: disable-msg=C0301

import socket
import threading
import time

class client(threading.Thread):

def connect(self):
HOST = "192.168.0.1"
PORT = 80
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
print "connect true"
return

def run(self):
self.connect()
return
print "thread 1"
client().start()
time.sleep(2)
print "thread 2"
client().start()
Теперь он отрабатывает как надо -
alex@kubu-book:~/development/PYTHON_projects$ python ./socks_th.py 
thread 1
connect true
thread 2
connect true
И на сетевом уровне тоже все как полагается -
 alex@kubu-book:~/development/PYTHON_projects$ sudo tcpdump -n host 192.168.0.1 and tcp and port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
22:09:58.224501 IP 192.168.0.5.51836 > 192.168.0.1.80: Flags [S], seq 2368199672, win 5840, options [mss 1460,sackOK,TS val 223165 ecr 0,nop,wscale 6], length 0
22:09:58.224720 IP 192.168.0.1.80 > 192.168.0.5.51836: Flags [S.], seq 3761446025, ack 2368199673, win 5792, options [mss 1460,sackOK,TS val 151564454 ecr 223165,nop,wscale 5], length 0
22:09:58.224760 IP 192.168.0.5.51836 > 192.168.0.1.80: Flags [.], ack 1, win 92, options [nop,nop,TS val 223165 ecr 151564454], length 0
22:09:58.225079 IP 192.168.0.5.51836 > 192.168.0.1.80: Flags [F.], seq 1, ack 1, win 92, options [nop,nop,TS val 223165 ecr 151564454], length 0
22:09:58.225634 IP 192.168.0.1.80 > 192.168.0.5.51836: Flags [F.], seq 1, ack 2, win 181, options [nop,nop,TS val 151564454 ecr 223165], length 0
22:09:58.225672 IP 192.168.0.5.51836 > 192.168.0.1.80: Flags [.], ack 2, win 92, options [nop,nop,TS val 223165 ecr 151564454], length 0
22:10:00.227030 IP 192.168.0.5.51837 > 192.168.0.1.80: Flags [S], seq 2392468491, win 5840, options [mss 1460,sackOK,TS val 223666 ecr 0,nop,wscale 6], length 0
22:10:00.227268 IP 192.168.0.1.80 > 192.168.0.5.51837: Flags [S.], seq 3794847646, ack 2392468492, win 5792, options [mss 1460,sackOK,TS val 151564955 ecr 223666,nop,wscale 5], length 0
22:10:00.227307 IP 192.168.0.5.51837 > 192.168.0.1.80: Flags [.], ack 1, win 92, options [nop,nop,TS val 223666 ecr 151564955], length 0
22:10:00.227470 IP 192.168.0.5.51837 > 192.168.0.1.80: Flags [F.], seq 1, ack 1, win 92, options [nop,nop,TS val 223666 ecr 151564955], length 0
22:10:00.227942 IP 192.168.0.1.80 > 192.168.0.5.51837: Flags [F.], seq 1, ack 2, win 181, options [nop,nop,TS val 151564955 ecr 223666], length 0
22:10:00.227989 IP 192.168.0.5.51837 > 192.168.0.1.80: Flags [.], ack 2, win 92, options [nop,nop,TS val 223666 ecr 151564955], length 0
^C
12 packets captured
12 packets received by filter
0 packets dropped by kernel
т е выходит с разных портов (51836 и 51837).

В данном феномене я еще не разобрался. такое ощущение, что инициализация объекта client происходит только один раз. Вероятно threading просто делает fork первого вызванного процесса/класса. Сейчас покопаюсь в книжном примере, приведенном вами выше.

Вероятно правильным решением будет отдельть объект, создающий socket от объекта, создающего новые потоки. Сделать 2 разных объекта.

PS
yurtaev
Пока копаю в документаций по сокетам, но не чего пока не нашёл.
Копатся надо в документации по threading относительно fork.



Отредактировано (Июнь 10, 2010 21:29:21)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version