🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: pl.comp.lang.python
8 messages
8 total messages Started by królewna Thu, 29 Apr 2010 11:02
Sockety, select i błąd
#27427
Author: królewna
Date: Thu, 29 Apr 2010 11:02
48 lines
2755 bytes
Witam

Dawno już nie pisałam bo nie miałam problemów póki co (za mało 
testowania jak się okazało). Otóż mój błąd występuje, gdy nastąpi 
połączenie na sockecie nieblokującym i próbuję coś z niego odczytać 
przed otrzymaniem danych. Otóż następujący kod (jest to już kod 
przykładowy a nie konkretnie wykorzystany):

socket.setdefaulttimeout(3)
listener = multiprocessing.connection.Listener(('localhost', 7000), 
backlog = 100)
while 1:	
	(input, [], []) = 
select.select([listener._listener._socket.fileno()],(),())
	con = listener.accept()
	lista.append(con)
	ip = listener.last_accepted
	#time.sleep(1)
	print ip
	try:
		data = con.recv()
	except Exception as e:
		print "Wyjatek", e.args
		con.close()
		continue
	con.close()

wyrzuca mi praktycznie caly czas wyjatek: "(11, 'Resource temporarily 
unavailable')". Obie rzeczy (klient i serwer) są uruchamiane na 
localhoscie więc opóźnienia są minimalne. Mimo wszystko wydaje się za 
duże dla programu. Klient łaczy się i od razu wysyła dane dane również 
od razu - bez żadnych opóźnień. Jednak zawsze dostaję ten błąd. Jeśli 
odkomentuję zakomentowaną linijkę ze sleep(1) to naraz błędy mi znikają 
i występują tylko jeśli w kliencie dam sleep między łaczeniem a 
wysyłaniem na więcej niż 1 sekundę. Wygląda to tak jakby pomimo 
ustawionego timeout'a żądanie odczytania danych następowało od razu i od 
razu wyrzucany jest wyjątek jeśli to odczytanie nie nastąpi.

Jednocześnie sockety blokujące w ogóle mnie nie interesują i nie wchodzą 
w grę. Chodzi o to, że będę masowo odbierała połączenia, które muszą być 
obsłużone jak najszybciej i w przypadku jeśli socket mi się zatrzyma na 
jakimś połączeniu, którego client nagle straci połączenie to będzie mi 
wisiał na tym połączeniu.

Czy jest jakiś sposób aby to elegancko rozwiązać?

pozdrawiam,
królewna
Re: Sockety, select i błąd
#27428
Author: Daniel Mróz
Date: Thu, 29 Apr 2010 12:59
59 lines
2931 bytes
On 29.04.2010, =?UTF-8?B?a3LDs2xld25h?= <królewna@ee.pl> wrote:
> Dawno już nie pisałam bo nie miałam problemów póki co (za mało 
> testowania jak się okazało). Otóż mój błąd występuje, gdy nastąpi 
> połączenie na sockecie nieblokującym i próbuję coś z niego odczytać 
> przed otrzymaniem danych. Otóż następujący kod (jest to już kod 
> przykładowy a nie konkretnie wykorzystany):
>
> socket.setdefaulttimeout(3)
> listener = multiprocessing.connection.Listener(('localhost', 7000), 
> backlog = 100)
> while 1:	
> 	(input, [], []) = 
> select.select([listener._listener._socket.fileno()],(),())
Wywal ten socket.setdefaulttimeout(3), dodaj czwarty argument do select.select()
o wartości 3.0 i zobacz czy mu się poprawi. Pamiętaj o obsłudze timeoutu.
BTW, skąd pewność że socket jest w trybie nieblokującym? Nie widzę żebyś
gdzieś ustawiała setblocking(0), a z multiprocessing.connection.Listener
nie miałem do czynienia.

> 	con = listener.accept()
> 	lista.append(con)
> 	ip = listener.last_accepted
> 	#time.sleep(1)
> 	print ip
> 	try:
> 		data = con.recv()
> 	except Exception as e:
> 		print "Wyjatek", e.args
> 		con.close()
> 		continue
> 	con.close()
Oj, jeśli gadasz po TCP (AF_INET, SOCK_STREAM), to musisz jeszcze popracować nad
tym kodem. W takim przypadku recv() może nie zwrócić wszystkich przesyłanych danych
i zamkniesz socket zanim odbierzesz wszystko. Dane powinnaś zczytywać do czasu, aż
nie dostaniesz nic. Będzie to oznaczało, że nadawca skończył. Zazwyczaj wygląda to
mniej więcej tak:

data = ''
while 1:
	fromsock = sock.recv()
	if fromsock:
		data += fromsock
		continue
	break
sock.shutdown(2)  # tego też nie robisz, a powinnaś
sock.close()

> Czy jest jakiś sposób aby to elegancko rozwiązać?
Użyć select.poll().


Pozdrawiam
Beorn

-- 
Daniel 'Beorn' Mróz <beorn@alpha.pl>    http://127.0.0.1/beorn
[GIT d s:- a-@ C++++ UL++++$ P+ L++++ E--- W+ N+++ o? K- w---]
[O- M- V!  PS+ PE++ Y+ PGP++ t- 5  X R !tv b+ DI D++ G++ e h*]
[                          r++  y+                           ]
Re: Sockety, select i błąd
#27429
Author: i0cus
Date: Sat, 01 May 2010 11:31
71 lines
4034 bytes
Witam,

Trochę strzelam w ciemno, ale nie mam jak sprawdzić w tej chwili,
możliwe, że zupełnie od rzeczy. ;-)


On 29 Kwi, 14:59, Daniel Mróz <be...@alpha.pl> wrote:
> On 29.04.2010, =?UTF-8?B?a3LDs2xld25h?= <króle...@ee.pl> wrote:> Dawno już nie pisałam bo nie miałam problemów póki co (za mało
> > testowania jak się okazało). Otóż mój błąd występuje, gdy nastąpi
> > połączenie na sockecie nieblokującym i próbuję coś z niego odczytać
> > przed otrzymaniem danych. Otóż następujący kod (jest to już kod
> > przykładowy a nie konkretnie wykorzystany):
>
> > socket.setdefaulttimeout(3)
> > listener = multiprocessing.connection.Listener(('localhost', 7000),
> > backlog = 100)
> > while 1:  
> >    (input, [], []) =
> > select.select([listener._listener._socket.fileno()],(),())
>
> Wywal ten socket.setdefaulttimeout(3), dodaj czwarty argument do select.select()
> o wartości 3.0 i zobacz czy mu się poprawi. Pamiętaj o obsłudze timeoutu.
> BTW, skąd pewność że socket jest w trybie nieblokującym? Nie widzę żebyś
> gdzieś ustawiała setblocking(0), a z multiprocessing.connection.Listener
> nie miałem do czynienia.

A czy to przypadkiem nie działa tak, że serwerowy socket jak jest
readable to można zrobić nieblokującego accept(), a żeby wołać na nim
recv() powinien być readable drugi raz? Timeout w select na 0 i będzie
szybko.


> >    con = listener.accept()
> >    lista.append(con)
> >    ip = listener.last_accepted
> >    #time.sleep(1)
> >    print ip
> >    try:
> >            data = con.recv()
> >    except Exception as e:
> >            print "Wyjatek", e.args
> >            con.close()
> >            continue
> >    con.close()
>
> Oj, jeśli gadasz po TCP (AF_INET, SOCK_STREAM), to musisz jeszcze popracować nad
> tym kodem. W takim przypadku recv() może nie zwrócić wszystkich przesyłanych danych
> i zamkniesz socket zanim odbierzesz wszystko. Dane powinnaś zczytywać do czasu, aż
> nie dostaniesz nic. Będzie to oznaczało, że nadawca skończył. Zazwyczaj wygląda to
> mniej więcej tak:
>
> data = ''
> while 1:
>         fromsock = sock.recv()
>         if fromsock:
>                 data += fromsock
>                 continue
>         break
> sock.shutdown(2)  # tego też nie robisz, a powinnaś
> sock.close()

IIRC nieblokujący socket zdaje się zwróci pustego stringa, jeśli nic
nie ma w buforze, bo musi zwrócić od razu. Co prawda od dwóch lat
używam tylko Twisted, ale wydaje mi się, że jeśli jest gniazdo
oznaczone jako readable przez select i zwróci nic, to wtedy nadawca
zakończył wysyłanie.


--
pozdrawiam,
SMG
Re: Sockety, select i błąd
#27434
Author: królewna
Date: Wed, 05 May 2010 06:29
43 lines
2720 bytes
W dniu 29.04.2010 14:59, Daniel Mróz pisze:

> Wywal ten socket.setdefaulttimeout(3), dodaj czwarty argument do select.select()
> o wartości 3.0 i zobacz czy mu się poprawi. Pamiętaj o obsłudze timeoutu.
> BTW, skąd pewność że socket jest w trybie nieblokującym? Nie widzę żebyś
> gdzieś ustawiała setblocking(0), a z multiprocessing.connection.Listener
> nie miałem do czynienia.

Niestety mi to nie bardzo pasuje, bo 3 sekundy na select'cie to dużo. 
Pomijając fakt, że zrobienie tego w ten sposób powoduje, że program wisi 
mi nie na select'cie a na listener.accept() co jest chyba zupełnie bez 
sensu. A socket jest ustawiany w tryb nonblocking gdy tylko ustawi się 
defaulttimeout na coś różnego od 0.0 (w moim przypadku 3).

> Oj, jeśli gadasz po TCP (AF_INET, SOCK_STREAM), to musisz jeszcze popracować nad
> tym kodem. W takim przypadku recv() może nie zwrócić wszystkich przesyłanych danych
> i zamkniesz socket zanim odbierzesz wszystko. Dane powinnaś zczytywać do czasu, aż
> nie dostaniesz nic. Będzie to oznaczało, że nadawca skończył. Zazwyczaj wygląda to
> mniej więcej tak:
>
> data = ''
> while 1:
> 	fromsock = sock.recv()
> 	if fromsock:
> 		data += fromsock
> 		continue
> 	break
> sock.shutdown(2)  # tego też nie robisz, a powinnaś
> sock.close()
>

Dlatego mówiłam, że to tylko przykładowy kod, który ma za zadanie 
wywołanie tego błędu a nie poprawne działanie.

>> Czy jest jakiś sposób aby to elegancko rozwiązać?
> Użyć select.poll().

Z tego co czytałam i próbowałam, to select.poll() dla mnie nic nie 
zmieni więc to nie jest rozwiązanie ;)

--
pozdrawiam
królewna
Re: Sockety, select i błąd
#27430
Author: królewna
Date: Wed, 05 May 2010 06:32
14 lines
1440 bytes
W dniu 01.05.2010 13:31, i0cus pisze:
>
> A czy to przypadkiem nie działa tak, że serwerowy socket jak jest
> readable to można zrobić nieblokującego accept(), a żeby wołać na nim
> recv() powinien być readable drugi raz? Timeout w select na 0 i będzie
> szybko.
>

Dokładnie jest tak jak mówisz. Tyle, że timeout 0 w select'cie dalej 
powoduje, że mam ten sam błąd.

--
pozdrawiam,
królewna
Re: Sockety, select i błąd
#27431
Author: Łukasz Rekucki
Date: Wed, 05 May 2010 07:15
23 lines
2087 bytes
On 5 Maj, 08:32, krĂłlewna <króle...@ee.pl> wrote:
> W dniu 01.05.2010 13:31, i0cus pisze:
>
>
> > A czy to przypadkiem nie działa tak, że serwerowy socket jak jest
> > readable to można zrobić nieblokującego accept(), a żeby wołać na nim
> > recv() powinien być readable drugi raz? Timeout w select na 0 i będzie
> > szybko.
>
> Dokładnie jest tak jak mówisz. Tyle, że timeout 0 w select'cie dalej
> powoduje, że mam ten sam błąd.

accept() zwraca *nowy* socket, który należy dodać do listy
przekazywanej do select() i dopiero jak select() stwierdzi, że ten
nowy socket jest gotowy do czytania można z niego bezpiecznie
skorzystać (oczywiście tylko raz i niekoniecznie przeczytamy wszystkie
wysłane dane).


>
> --
> pozdrawiam,
> królewna
Re: Sockety, select i błąd
#27432
Author: królewna
Date: Wed, 05 May 2010 08:24
30 lines
2516 bytes
W dniu 05.05.2010 09:15, Łukasz Rekucki pisze:
>
> accept() zwraca *nowy* socket, który należy dodać do listy
> przekazywanej do select() i dopiero jak select() stwierdzi, że ten
> nowy socket jest gotowy do czytania można z niego bezpiecznie
> skorzystać (oczywiście tylko raz i niekoniecznie przeczytamy wszystkie
> wysłane dane).

Dokładnie tak robię. A za dokumentacją multiprocessing.connection
recv()
     Return an object sent from the other end of the connection using 
send(). Raises EOFError if there is nothing left to receive and the 
other end was closed.

Z czego rozumiem, że za jednym recv() powinnam odczytać wszystko, co 
zostało wysłane przy pomocy jednego send(). Jeśli nic nie wysłałam przez 
send() to powinnam dostać EOFError.

Specjalnie dla tych metod wysyłam sobie tablicę 100k elementową aby to 
sprawdzić. Przy "niedługich" danych (tablica 20k elementowa)jest ok 
jednak przy tablicy 30k elementowej jest już błąd. Skąd mam wiedzieć 
jaki jest limit danych, które mogę wysłać? Pół biedy jeśli jest to jakiś 
limit zaimplementowany na stałe (choć i to by było niesmaczne) ale co 
jeśli to jest błąd związany np z aktualną przepustowością sieci (a ja 
przesyłam póki co dane w obrębie localhosta więc sieć jest tu 
praktycznie najszybsza jaka będzie:) )?

--
pozdrawiam
królewna
Re: Sockety, select i błąd
#27433
Author: królewna
Date: Wed, 05 May 2010 08:29
8 lines
1413 bytes
I poprawka, jeśli np tą 20k elementową tablicę wysyłam jako pierwszą a 
później jakiś krótki tekst to przy tej tablicy otrzymuję "Resource 
temporarily unavailable". Nie za bardzo już wiem jak to mam łapać i 
właściwie na czym polega błąd.

--
pozdrawiam
królewna
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads