[python] threads weer stoppen? socket los laten

Pagina: 1
Acties:
  • 110 views sinds 30-01-2008
  • Reageer

  • killercow
  • Registratie: Maart 2000
  • Laatst online: 15:38
Ik ben bezig met een threaded servertje in python,

Nu heb ik van alles en nog wat al voor elkaar.
Ik kan threads maken, connecten, data sturen, en weer terug krijgen, en dit ook vanuit meerdere clients tegeleik doen.

Tevens lijkt het goed te gaan met de threads, de server blijft reageren, ook nadat de 5 aangemaakte threads allemaal eens gebruikt zijn.

Ik heb de volgende tutorial gebruikt, maar er zit nog een boel abracadbra in.

http://www.devshed.com/c/...ic-Threading-in-Python/1/

Ik vraag me bijvoorbeeld af hoe ik een thread stop, zodat deze opnieuw gebruikt kan worden,
(ik denk dat ik dit niet nodig heb, want het lijkt te werken, maar hoe signallen de threads dan naar de bse thread dat ze klaar zijn om een nieuwe client te verwerken?

Daarnaast is het behoorlijk irritant dat het script geen sockets meer los laat, dit zorgt er voor dat ik constant een nieuwe poort moet gebruiken.

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/python
import sys,os,threading,socket,getopt,string
import Queue

portnumber=1080
threads=5

# the list of chunkservers and their addresses
chunkservers={};
chunkservers[1]=('127.0.0.1',1082)
chunkservers[2]=('127.0.0.1',1083)
# where to find each file, fileid,chunkserverid
files={};
files['index.html']=(1,1)
files['test.html']=(2,1)
files['test/test.html']=(3,1)
files['server2/test.html']=(4,2)
files['server2/testjes.html']=(4,2)

try:
    opts, args = getopt.getopt(sys.argv[1:], "t:p:", ["port=", "threads="])
except getopt.GetoptError:
    # print help information and exit:
    print 'Sorry, no arguments given or understood'
    sys.exit(2)


for o, a in opts:
    if o in ("-p", "--port="):
        portnumber = long(a,10)
    if o in ("-t", "--threads="):
        threads = int(a,10)

print 'MasterServer, starting '+str(threads)+" threads on port "+str(portnumber)

class ClientThread ( threading.Thread ):
    def run ( self ):
        run=True;
        while run==True:
            # Get a client out of the queue
            client = clientPool.get()
            if client != None:
                print 'Received connection:', client[1][0]
                data = client[0].recv(1000)
                if data:
                    data=data.join( data.strip().split() )
                    if data=='stop':
                        run=False
                        return true;
                    print 'received "',data,'" from ',client[1][0],' connected on port ',client[1][1];
                    try:
                        fileinfo=files[data]
                        #returndata='test'
                        returndata="fileid:"+str(fileinfo[0])+"\n"
                        returndata+="serverip:"+chunkservers[ fileinfo[1] ][0]+"\n"
                        returndata+="serverport:"+str(chunkservers[ fileinfo[1] ][1])+"\n"
                        print "fileid:"+str(fileinfo[0])+"\nserverip:"+chunkservers[ fileinfo[1] ][0]+"\nserverport:"+str(chunkservers[ fileinfo[1] ][1])
                    except:
                        returndata="404 Invalid file\n";
                        print "could not send file ",data;
                    
                    client[0].send(returndata)
                    client[0].close();
                    del client;

clientPool = Queue.Queue ( 0 )
for x in xrange ( threads ):
    ClientThread().start()


#create an INET, STREAMing socket
serversocket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#bind the socket to a public host,
# and a well-known port
try:
    serversocket.bind((socket.gethostname(), portnumber))
    #become a server socket
    serversocket.listen(threads)

    while True:
        clientPool.put ( serversocket.accept() )
except:
    print 'cannot open socket'
    sys.exit(2)
    for x in xrange ( threads ):
        ClientThread().stop();


Hoewel het op got niet de bedoeling is dat er een plak code gedumpt wordt welke dan door de gotters gedebugged wordt (de code werkt), zou ik toch wat nederlandse uitleg kunnen gebruiken over wat nu precies wat doet.

openkat.nl al gezien?


  • TeeDee
  • Registratie: Februari 2001
  • Laatst online: 14:04

TeeDee

CQB 241

Je stopt nu een thread. Is het niet handiger om een thread te releasen of iets dergelijks? In mijn extreem karige python-threading-crash-course-van-een-inmiddels-vertrokken-stagair kan ik me herinneren dat zoiets moest.

Misschien kan je hier nog wat informatie uithalen.

[ Voor 23% gewijzigd door TeeDee op 23-01-2007 15:37 ]

Heart..pumps blood.Has nothing to do with emotion! Bored


  • killercow
  • Registratie: Maart 2000
  • Laatst online: 15:38
TeeDee schreef op dinsdag 23 januari 2007 @ 15:35:
Je stopt nu een thread. Is het niet handiger om een thread te releasen of iets dergelijks? In mijn extreem karige python-threading-crash-course-van-een-inmiddels-vertrokken-stagair kan ik me herinneren dat zoiets moest.

Misschien kan je hier nog wat informatie uithalen.
Okey,

De thread in leven houden is simpel genoeg,
Ik denk dat ik eigenlijk de thread een nieuwe client connectie van de stack moet laten plukken, en hem dus eigenlijk helemaal niet wil stoppen.

Dan hou ik alleen het probleem nog over, hoe stop ik dit script, zijn threads, en release ik de socket?
Ik kan natuurlijk elke thread naar STOP laten luisteren, maar dan moet ik ze nog alsnog allemaal stoppen enzo. (en dan blijft de server die de threads start alsnog leven.)

openkat.nl al gezien?


  • DroogKloot
  • Registratie: Februari 2001
  • Niet online

DroogKloot

depenisvanjezus

Zorg dat de socket/s SO_REUSEADDR als property heeft/hebben.

[ Voor 8% gewijzigd door DroogKloot op 23-01-2007 16:38 ]


  • killercow
  • Registratie: Maart 2000
  • Laatst online: 15:38
DroogKloot schreef op dinsdag 23 januari 2007 @ 16:38:
Zorg dat de socket/s SO_REUSEADDR als property heeft/hebben.
Maar dat geeft toch eigenlijk de poort weer een beetje vrij, terweil hij dat niet zou moeten zijn? (hij is immers nog in gebruik)

Ik wil de poort netjes releases als het programma afsluit, maar het programma wil maar niet stoppen. (door de loop aan het einde), hoe communiceer ik nu vanuit de threads naar de master dat alles gestopt moet worden, Or hoe communiceer ik via de shell van het programma, aan het programma dat het alles (inc threads) moet stoppen. (want crtl-c geeft de sockets niet vrij)

Ik heb nu de volgende aanpassigen gedaan:
binnen de thread een optie op een var om te gooien naar false.

En in de main loop de for stoppen op het moment dat deze var naar false gezet is.
Ik ga vanavond m'n scope's nog maar eens nalezen, want ik heb nog geen idee hoe ik dit aan de gang ga krijgen, maar het lijkt mij wel de juiste manier.

In de thread:
Python:
1
2
3
4
5
if data=='stop':
    run=False
    client[0].send("Ok, master stopping")
    client[0].close();
    del client;


In de main loop:
Python:
1
2
3
4
5
6
7
8
run=True;
while run==True:
    clientPool.put ( serversocket.accept() )
    # if run == false, stop threads, and close the socket.
    for x in xrange ( threads ):
        ClientThread().stop();
    serversocket.close();
    print 'server stopped clean'

[ Voor 36% gewijzigd door killercow op 24-01-2007 10:33 ]

openkat.nl al gezien?


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
Je hebt een hoop verschillende vragen, en dat maakt ze beantwoorden niet makkelijker. Ook heb ik het idee dat je een hoop code gekopieerd hebt die je niet goed begrijpt. Code bekijken van anderen is een goede manier om te leren, maar met klakkeloos overnemen schiet je niets op. Het is waarschijnlijk beter om je code opnieuw op te bouwen, en daarbij goed na te denken wat je precies doet, en waarom.

Een aantal opmerkingen.
• Je hebt een lokale variabele 'run' in je thread, die je op false zet als je een "stop" commando ontvangt via je socket. Die variabele is ook de enige manier waarop je uit je lus kunt komen. Echter, direct nadat je run op True zet, return je uit je threadfunctie. Met andere woorden: die hele run-variabele heeft geen enkel nut, want zolang je in je threadfunctie zit, is 'ie altijd true.

• Verder volgt daaruit dat als je "stop" ontvangt, je alleen één thread uit je threadpool afsluit. Je sluit dus niet de verbinding, maar de hele thread! Als je alle threads in de pool op deze manier hebt opgeruimd, loopt je programma effectief vast omdat er geen threads meer zijn om binnenkomende connecties af te handelen. Desalniettemin sluit je de applicatie op deze manier niet af. Dat kan nooit de bedoeling zijn.
hoe signallen de threads dan naar de bse thread dat ze klaar zijn om een nieuwe client te verwerken?
Dat signaleren ze niet. Ze halen gewoon connecties uit de queue, als dat kan (zo niet, dan wachten ze vanzelf). De main thread gooit die connecties in de queue in de wetenschap dat ze er ooit wel weer eens uitgehaald worden. Een nette manier om de applicatie vanuit de main thread af te sluiten (of vanuit een andere thread, wat ook prima werkt) is dan ook om een speciale waarde in de queue te zetten; None is wel aardig in dit geval:
Python:
1
2
3
4
5
6
7
8
9
10
11
def run():
    while True:
        client = clientPool.get()
        if not client:
             # Exiting thread.
             break
        .... connection handling code here ....

def stop_threads():
    for _ in xrange (threads):
    clientPool.put(None)

Merk op dat de applicatie nu pas daadwerkelijk afgesloten wordt, nadat alle draaiende connecties afgehandeld zijn. Bestaande connecties afbreken is lastiger.

  • killercow
  • Registratie: Maart 2000
  • Laatst online: 15:38
Soultaker schreef op woensdag 24 januari 2007 @ 12:07:
Je hebt een hoop verschillende vragen, en dat maakt ze beantwoorden niet makkelijker. Ook heb ik het idee dat je een hoop code gekopieerd hebt die je niet goed begrijpt. Code bekijken van anderen is een goede manier om te leren, maar met klakkeloos overnemen schiet je niets op. Het is waarschijnlijk beter om je code opnieuw op te bouwen, en daarbij goed na te denken wat je precies doet, en waarom.
Ik heb inderdaad de tutorial gevolgd die ik gelinkt heb, zoals je kunt zien is een boel code het zelfde, maar ook een boel anders. Threading is mij redelijk bekend, python niet zo erg.
Opnieuw beginnen is geen punt, ik wil er immers van leren, de rest is atm bijzaak.
Een aantal opmerkingen.
• Je hebt een lokale variabele 'run' in je thread, die je op false zet als je een "stop" commando ontvangt via je socket. Die variabele is ook de enige manier waarop je uit je lus kunt komen. Echter, direct nadat je run op True zet, return je uit je threadfunctie. Met andere woorden: die hele run-variabele heeft geen enkel nut, want zolang je in je threadfunctie zit, is 'ie altijd true.
Check, vandaar dat ik m'n scopes ging uitpluizen, run kan wel door een thread of false gezet worden, maar als de main thread niet de zelfde var bekijkt gebeurt er inderdaad erg weinig (behalve de return die de thread stopt)
• Verder volgt daaruit dat als je "stop" ontvangt, je alleen één thread uit je threadpool afsluit. Je sluit dus niet de verbinding, maar de hele thread! Als je alle threads in de pool op deze manier hebt opgeruimd, loopt je programma effectief vast omdat er geen threads meer zijn om binnenkomende connecties af te handelen. Desalniettemin sluit je de applicatie op deze manier niet af. Dat kan nooit de bedoeling zijn.
Idd, ik wil alle threads afsluiten, door een signaal te geven, (permissies even voor wat ze zijn), en dan netjes de socket afsluiten, en de main thread stoppen. (aka de while true loop aan het einde op false krijgen)
[...]

Dat signaleren ze niet. Ze halen gewoon connecties uit de queue, als dat kan (zo niet, dan wachten ze vanzelf). De main thread gooit die connecties in de queue in de wetenschap dat ze er ooit wel weer eens uitgehaald worden. Een nette manier om de applicatie vanuit de main thread af te sluiten (of vanuit een andere thread, wat ook prima werkt) is dan ook om een speciale waarde in de queue te zetten; None is wel aardig in dit geval:
Duidelijk, ik dacht al dat dit zo werkte. (pool.get() kind of gave it away)

Kunnen de losse threads dit ook voor de hele pool? of is het verstandig dit naar de main thread te sturen via een global var, en dan de main thread dit te laten doen?
Python:
1
2
3
4
5
6
7
8
9
10
11
def run():
    while True:
        client = clientPool.get()
        if not client:
             # Exiting thread.
             break
        .... connection handling code here ....

def stop_threads():
    for _ in xrange (threads):
    clientPool.put(None)

Merk op dat de applicatie nu pas daadwerkelijk afgesloten wordt, nadat alle draaiende connecties afgehandeld zijn. Bestaande connecties afbreken is lastiger.
Bestaande connecties af laten wikkeleing is wel handig, (behalve dat bij een restart het wellicht er lang duurt voordat er weer nieuwe connecties afgewerkt worden), prio 2 zeg maar. (eerst snappen wat ik nu doe).

In ieder geval bedankt, ik post eventuele vervolg vragen ook wel weer hier.
Op de threading na begint het programma al aardig te doen wat het moet doen, (files serven, sums checken enzo, maar de volgende problemen hiermee beginnen zich ook aan te dienen)

openkat.nl al gezien?

Pagina: 1