Forum: PC-Programmierung Python TCP Verbindung einmal senden dann schließen


von Sven (Gast)


Lesenswert?

Hallo,
ich habe hier folgenden Code:
1
import socket
2
import sys
3
4
#Globale Variablen
5
port_TCP = 5000
6
7
8
#Main function
9
print('Program is started')
10
11
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
12
print('Socket created')
13
s.bind(('', port_TCP))
14
s.listen(1)
15
try:
16
    while True:
17
        komm, addr = s.accept()
18
        while True:
19
            command = komm.recv(1024)
20
            if not command:
21
                komm.close
22
                break
23
            print 'Nachricht [%s]: %s' % (addr[0], command)
24
            komm.send('Befehl erhalten: ' + command)
25
            if command == 'NULL':
26
                komm.close()
27
        
28
finally:
29
    s.close()
30
31
print(command)                  
32
print ('123')
33
raw_input('Eingabe...')

Ich möchte einmal einen Befehl per TCP an diesen Server senden (Mache 
ich zwekcs Testzwekce per Packet Sender) und danach soll er die 
Verbindung beenden und im Programmcode fortfahren.
Wenn er den Befehl (Vier Buchstaben) erhált wird dieser Befehl richtig 
zurückgesendet, dann wird aber nichts mehr gemacht. Ich kann danach 
einfach weitere Befehle senden. Das will ich aber nicht mehr. Er soll 
dann die Ausgabe unten machen.

: Verschoben durch User
von Rainer U. (r-u)


Lesenswert?

Hmm, ich kenn zwar python nicht, aber

- wofür benutzt Du 2 verschachtelte Schleifen? / was bedeutet "while 
True" für Dich?

- Kommt nach einem Try nicht ein "catch" / except ?

von rk (Gast)


Lesenswert?

Soll er für weitere Verbindungen zur Verfügung stehen, oder nie wieder 
antworten?

von rk (Gast)


Lesenswert?

Wenn er immer wieder reagieren soll, könnte es inj etwa so aussehen:
1
#Main function
2
print('Program is started')
3
4
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
5
print('Socket created')
6
s.bind(('', port_TCP))
7
s.listen(1)
8
try:
9
    while True:
10
        komm, addr = s.accept()
11
        command = komm.recv(1024)
12
        if command is not None and len(command) > 0:
13
            print 'Nachricht [%s]: %s' % (addr[0], command)
14
            komm.send('Befehl erhalten: ' + command)
15
            komm.close()
16
17
            print(command)                  
18
            print ('123')
19
            raw_input('Eingabe...')
20
21
except:
22
    print "Fehler aufgetreten..."
23
        
24
finally:
25
    s.close()

von Sheeva P. (sheevaplug)


Lesenswert?

Sven schrieb:
> Ich möchte einmal einen Befehl per TCP an diesen Server senden (Mache
> ich zwekcs Testzwekce per Packet Sender) und danach soll er die
> Verbindung beenden und im Programmcode fortfahren.

Das ist jetzt schon die zweite Frage, in der Du irgendwelche komischen 
Sachen mit Deinem Netzwerk machst. Magst Du uns nicht vielleicht einmal 
erzählen, was Du eigentlich vorhast?

Was den Code angeht, so ist er an zwei Stellen kaputt. Auf den ersten 
Fehler hat "Rainer Unsinn" Dich bereits hingewiesen, nämlich: was 
bedeutet "while True" für Dich? Und zweitens: was ist "komm.close"?

von Sven (Gast)


Lesenswert?

Sheeva P. schrieb:
> Sven schrieb:
>> Ich möchte einmal einen Befehl per TCP an diesen Server senden (Mache
>> ich zwekcs Testzwekce per Packet Sender) und danach soll er die
>> Verbindung beenden und im Programmcode fortfahren.
>
> Das ist jetzt schon die zweite Frage, in der Du irgendwelche komischen
> Sachen mit Deinem Netzwerk machst. Magst Du uns nicht vielleicht einmal
> erzählen, was Du eigentlich vorhast?
>
> Was den Code angeht, so ist er an zwei Stellen kaputt. Auf den ersten
> Fehler hat "Rainer Unsinn" Dich bereits hingewiesen, nämlich: was
> bedeutet "while True" für Dich? Und zweitens: was ist "komm.close"?

Ich erhalte einen Befehl per TCP. Diesen muss ich auswerten und 
anschlißend entsprechnd einen Befehl per UDP weitersenden. Deshalb nur 
einen Befehl erhalten per TCP. Das hab ich jetzt auch soweit 
hinbekommen. Diesen Befehl muss ich jetzt auswerten. Problem dabei gerad 
ist das ich zum Beispiel

CAEE

bekomme. Wenn ich jetzt folgende Abfrage machen will

if (command[0] == 'C')

kommt immer die Meldung: IndexError: string index out of range

Was muss ich tun damit das tut. Bin leider absoluter Neuling in Python.

von Bernhard R. (bernhard_r28)


Lesenswert?

Zu 1:
Wenn du den Socket schließen möchtest, solltest du nach dem 
erfolgreichem Empfangen deines Strings die while Schleife verlassen. 
(Stichwort break)

Zu 2:
Du übergibst deiner if Abfrage gerade einen leeren String, und das mag 
sie nicht...

Hierzu ein kleines Beispiel (Python 3.x)
1
def testing(str):
2
    print("Testing: " + str)
3
    if str[0] == 'A':
4
        print("got it!")
5
6
7
testing('AFFE')
8
testing('DOOF')
9
testing('')

Viel Erfolg,

Bernhard

von MaWin (Gast)


Lesenswert?

Anhand dieses Codefetzens wird dir wahrscheinlich kaum jemand
helfen können. An welcher Stelle hast du diese Zeile eingefügt?
Ganzen Code zeigen.

PS: Die Bedingung brauchst du nicht in Klammern einzuschließen.

von Sven (Gast)


Lesenswert?

Bernhard R. schrieb:
> Zu 1:
> Wenn du den Socket schließen möchtest, solltest du nach dem
> erfolgreichem Empfangen deines Strings die while Schleife verlassen.
> (Stichwort break)
>
> Zu 2:
> Du übergibst deiner if Abfrage gerade einen leeren String, und das mag
> sie nicht...
>
> Hierzu ein kleines Beispiel (Python 3.x)def testing(str):
>     print("Testing: " + str)
>     if str[0] == 'A':
>         print("got it!")
>
> testing('AFFE')
> testing('DOOF')
> testing('')
>
> Viel Erfolg,
>
> Bernhard

Ich verwende Python 2.7. Funktioniert das dann trotzdem so wie in deinem 
Beispiel gezeigt.

Hier nochmal der ganze Code.
1
receive = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
2
print('Socket created')
3
receive.bind(('', port_TCP))
4
receive.listen(1)
5
6
komm, addr = receive.accept()
7
print('Connection adress is: [%s]' % (addr[0]))
8
while 1:
9
        command = (komm.recv(1024))
10
        if not command:
11
                komm.close
12
                break
13
        print 'Command [%s]: %s' % (addr[0], command)
14
        komm.send('Befehl erhalten: ' + command)
15
komm.close() #TCP-Verbindung beenden
16
17
18
if (command[0] == 'C'):
19
        print('Konfiguration')
20
elif (command[0] == 'R'):
21
        print('Daten lesen')
22
elif (command[0] == 'W'):
23
        print('Daten schreiben')
24
else:
25
        print('Wrong command')


Grüsse

von Sven (Gast)


Lesenswert?

Sorry für den Doppelpost.

@Bernhard: Hab dein Beispiel kurz getestet. Das versteh ich soweit. Aber 
ich erhalte doch per TCP keinen leeren String sondern in der Variable 
command steht doch etwas drinne.


Grüsse

von Bernhard R. (bernhard_r28)


Lesenswert?

Ob du wirklich keinen leeren string bekommst würde ich mal testen:
1
if command == '':
2
    print('empty string!!!')
3
else:
4
    #break the while loop
5
    break

Ansonsten tut das Code Snippet bei mir ...

von Sven (Gast)


Lesenswert?

Bernhard R. schrieb:
> Ob du wirklich keinen leeren string bekommst würde ich mal
> testen:if command == '':
>     print('empty string!!!')
> else:
>     #break the while loop
>     break
>
> Ansonsten tut das Code Snippet bei mir ...

Bernhard R. schrieb:
> Ob du wirklich keinen leeren string bekommst würde ich mal
> testen:if command == '':
>     print('empty string!!!')
> else:
>     #break the while loop
>     break
>
> Ansonsten tut das Code Snippet bei mir ...

Also ich erhalte tatsächlich einen leeren String. Dann ist klar das die 
Fehlermeldung kommt. Aber weiter oben im Code gebe ich ja das command 
aus, also den Inhalt welchen ich erhalten habe. Dann kann der ja 
eigentlich gar nicht leer sein. Außer das er nicht übergeben wird. 
Vielleicht pack ich das ganze mal in eine Funktion und übergebe am ende 
das command mit "return command"
Oder hast du noch eine andere Lösung bzw. den Fehler

von Tek (Gast)


Lesenswert?

Was passiert wenn Du deine While Schleife hier abbrichst...
1
if not command:
2
   komm.close
3
   break

und dann hierhin kommst?
1
if (command[0] == 'C'):
2
      print('Konfiguration')
3
elif (command[0] == 'R'):
4
      print('Daten lesen')
5
elif (command[0] == 'W'):
6
      print('Daten schreiben')
7
else:
8
      print('Wrong command')

von Bernhard R. (bernhard_r28)


Lesenswert?

Ich habs gerade nochmal mit netcat versucht.
Ein leerer String sendet mir trotzdem ein 0x0a (line feed) mit.
Teste das mal mit print(command.__len__()).
Bei mir kam 1 raus...

von MaWin (Gast)


Lesenswert?

Sven schrieb:
> while 1:
>         command = (komm.recv(1024))
>         if not command:
>                 komm.close
>                 break

Du springst hier aus der while-Schleife, wenn "command" leer ist!
Das dürfte das Gegenteil von dem sein, was du eigentlich willst.

von Sheeva P. (sheevaplug)


Lesenswert?

Sven schrieb:
> Ich erhalte einen Befehl per TCP. Diesen muss ich auswerten und
> anschlißend entsprechnd einen Befehl per UDP weitersenden.

Das hatte ich gestern schon verstanden. ;-)

Nein, im Ernst: Dein per TCP erhaltener Befehl kommt ja irgendwo her, 
also vermutlich von einem anderen Netzwerkgerät. Die Auswertung dieses 
Befehls hat vermutlich einen Sinn wie etwa eine Filterung oder 
Konvertierung. Und das Weitersenden des Befehls dürfte doch vermutlich 
irgendein Ziel haben, möglicherweise ein anderes Netzwerkgerät. Sind 
meine Vermutungen soweit richtig? Wenn ja: gut, wenn nicht: bitte 
korrigiere mich.

Um Dir jetzt einen vernünftigen Rat zu geben, wäre es durchaus sinnvoll, 
etwas mehr über den Hintergrund Deiner Fragestellung zu erfahren. Also 
beispielsweise, um welche Art von Netzwerkgeräten es bei dem TCP-Client 
und dem UDP-Server geht, wie die Auswertung aussehen soll, und welchen 
tieferen Sinn die ganze Veranstaltung haben soll. Anders gesagt: mit ein 
wenig mehr Hintergrundinformationen könnte man Dir wesentlich schneller 
und zweifellos auch besser helfen.

> Deshalb nur einen Befehl erhalten per TCP.

Siehst Du, da geht (für mich) die Unsicherheit schon los: was genau 
meinst Du damit? Willst Du genau einen Befehl per TCP erhalten, diesen 
auswerten, und dann den TCP-Server beenden? Oder soll der TCP-Server 
nach Empfang und Auswertung des Befehls auf weitere Befehle lauschen?

Dabei stellt sich eine Reihe weiterer Fragen, zum Beispiel, ob es 
möglich ist, daß der TCP-Server mehrere Befehle gleichzeitig, oder 
sonstwie einen zweiten Befehl erhält, bevor der erste fertig ausgewertet 
und verarbeitet ist? Ob der UDP-Server, an den Du Deine Weiterleitung 
schickst, Dir eine Bestätigung zurückschickt, daß er Deinen 
weitergeleiteten Befehl empfangen hat? Warum Du wegen im Prinzip 
derselben Frage noch einen zweiten Thread eröffnest, obwohl Du Dich im 
ersten Thread nicht mehr gemeldet hast?

> Das hab ich jetzt auch soweit hinbekommen.

Sei mir nicht böse, aber Dein Code sieht für mich nicht danach aus, als 
ob Du das zuverlässig hinbekommen hättest. ;-)

> Was muss ich tun damit das tut. Bin leider absoluter Neuling in Python.

Ich bin mir ehrlich gesagt nicht ganz sicher, ob Netzwerkprogrammierung 
wirklich der beste Weg ist, um eine Programmiersprache zu lernen.

von Sheeva P. (sheevaplug)


Lesenswert?

Tek schrieb:
> Was passiert wenn Du deine While Schleife hier abbrichst...
>
>
1
> if not command:
2
>    komm.close
3
>    break
4
>

Leute! Bin ich wirklich der Einzige, dem "komm.close" auffällt?

von Sheeva P. (sheevaplug)


Lesenswert?

Bernhard R. schrieb:
> Ich habs gerade nochmal mit netcat versucht.
> Ein leerer String sendet mir trotzdem ein 0x0a (line feed) mit.
> Teste das mal mit print(command.__len__()).

Es gilt als sehr schlechter Stil, Variablen, Funktionen und Operatoren 
zu benutzen, die per Konvention "private" sind. Daher lieber nicht
1
command.__len__()

sondern stattdessen bitte
1
len(command)

benutzen.

von Sven (Gast)


Lesenswert?

Sheeva P. schrieb:
> Sven schrieb:
>
> Nein, im Ernst: Dein per TCP erhaltener Befehl kommt ja irgendwo her,
> also vermutlich von einem anderen Netzwerkgerät. Die Auswertung dieses
> Befehls hat vermutlich einen Sinn wie etwa eine Filterung oder
> Konvertierung. Und das Weitersenden des Befehls dürfte doch vermutlich
> irgendein Ziel haben, möglicherweise ein anderes Netzwerkgerät. Sind
> meine Vermutungen soweit richtig? Wenn ja: gut, wenn nicht: bitte
> korrigiere mich.
>
> Um Dir jetzt einen vernünftigen Rat zu geben, wäre es durchaus sinnvoll,
> etwas mehr über den Hintergrund Deiner Fragestellung zu erfahren. Also
> beispielsweise, um welche Art von Netzwerkgeräten es bei dem TCP-Client
> und dem UDP-Server geht, wie die Auswertung aussehen soll, und welchen
> tieferen Sinn die ganze Veranstaltung haben soll. Anders gesagt: mit ein
> wenig mehr Hintergrundinformationen könnte man Dir wesentlich schneller
> und zweifellos auch besser helfen.
>
>> Deshalb nur einen Befehl erhalten per TCP.
>
> Siehst Du, da geht (für mich) die Unsicherheit schon los: was genau
> meinst Du damit? Willst Du genau einen Befehl per TCP erhalten, diesen
> auswerten, und dann den TCP-Server beenden? Oder soll der TCP-Server
> nach Empfang und Auswertung des Befehls auf weitere Befehle lauschen?
>
> Dabei stellt sich eine Reihe weiterer Fragen, zum Beispiel, ob es
> möglich ist, daß der TCP-Server mehrere Befehle gleichzeitig, oder
> sonstwie einen zweiten Befehl erhält, bevor der erste fertig ausgewertet
> und verarbeitet ist? Ob der UDP-Server, an den Du Deine Weiterleitung
> schickst, Dir eine Bestätigung zurückschickt, daß er Deinen
> weitergeleiteten Befehl empfangen hat? Warum Du wegen im Prinzip
> derselben Frage noch einen zweiten Thread eröffnest, obwohl Du Dich im
> ersten Thread nicht mehr gemeldet hast?


Hallo,

also nochmal etwas genauer vielleicht. Der TCP Client ist momentan noch 
nicht ausgereift, dient aber nur dazu Befehle zu senden bzw. wie du 
schon gesagt hast am Ende eine quittierung zu erhalten. Deshalb kann ich 
hier im ersten Schritt mit dem Programm Packet Sender arbeiten.
Es ist so das ich eben einen Befehl sende (z.B. CAII) welcher für 
Konfiguration all steht. Dann soll dieser Befehl von meinem TCP Server 
empfangen werden. Außerdem muss ich über diesen TCP Server vermutlich zu 
aller erst eine IP Adresse senden, welches Gerät konfiguriert werden 
muss. Das ganze befindet sich später an einem Computer alles, also nicht 
übers Local-Netz hinaus soweit ich das verstanden habe.
So der Befehl bzw. die IP Adresse werden dann verwendet um einen 
definierten Befehl (den weiß ich selbst noch nicht so genau) im nächsten 
schritt per UDP an einen zweiten Client so senden. Hier handelt es sich 
um einen Sensor der angesprochen und konfiguriert wird bzw. auch 
ausgelesen werden kann. Ist der befehl dort angekommen wird automatisch 
der befehl vom Sensor quittiert und per UDP wieder empfangen. Diese 
Quittierung soll dann wieder an den TCP Client gesendet werdern so das 
dieser weiß, der Befehl wurde ausgeführt.
Ic hoffe ich konnte damit etwas licht ins dunkle bringen. Habe leider 
immer noch keine Lösung für mein Problem mit der variable "command".


Grüße

von Sven (Gast)


Lesenswert?

Habe jetzt einfach mal mit Funktionen gearbeitet welche ich in die TCP 
Verbindung eingebaut habe:

1
def funktion_1():
2
        print('Das ist C')
3
        return
4
5
def funktion_2():
6
        print('Das ist A')
7
        return
8
9
10
#Main function
11
print('Program started')
12
ip_adress = raw_input('Enter IP-Adress from BNI: ') #IP Adresse BNI-Master
13
14
while 1:
15
        #Start TCP-Connection
16
        receive = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
17
        print('Socket created\nWaiting for Communication to Client')        
18
        receive.bind(('', port_TCP))
19
        receive.listen(1)
20
21
        komm, addr = receive.accept()
22
        print('Connection adress is: [%s]' % (addr[0]))
23
        while 1:
24
                command = (komm.recv(1024))
25
                print 'Command: %s' % (command)
26
                komm.send('Befehl erhalten: ' + command)
27
                print 'Command: %s' % (command)
28
                if command[0] == 'C':
29
                        funktion_1()
30
                        break
31
                elif command[0] == 'A':
32
                        funktion_2()
33
                        break
34
                else:
35
                        print('wrong')
36
                        break

So erkennt er jetzt ohne Probleme ob zum Beispiel ein C oder ein A vorne 
steht. Das bedeutet doch das ich in die Funktion_1 dann meine weiteren 
Aufgaben schreiben kann. Oder gibt es einen besseren weg? Durch das 
break wird ja anschließend die while Schleife beendet. Aber meine TCP 
Verbindung ja eigentlich nicht? Macht es sinn diese zu beenden und beim 
senden der quittierung die verbindung neu aufzubauen oder kann ich diese 
problemlos offen halten und trotzdem eine UDP verbindung aufmachen und 
senden? Quasi am Ende dann meine Verbindungen erst alle schließen?


Grüße

von imonbln (Gast)


Lesenswert?

Warum nimmst du nicht zumindest für die TCP Verbindung einen 
SocketServer, dieser sollte die das TCP Handling abnehmen und du kannst 
dich um das erkennen der Befehle und das UDP handling kümmern. Außerdem 
finde  ich dein if command[0] == 'C': sieht sehr nach basteln aus :)

ich würde dir hier vorschlagen ein dict zu verwenden key ist der gültige 
Befehl und value ist die dann zu rufende funktion.  denn Funktionen sind 
in Python auch nur Objekte d.h. du kannst sie auch so verwenden.
1
import SocketServer
2
3
4
class MyTCPHandler(SocketServer.BaseRequestHandler):
5
    def handle(self):
6
        command = { 'A': function1,
7
                    'B': function2}
8
        exit = False
9
        try:
10
            while not exit:
11
                self.data = self.request.recv(1024).strip()
12
                if 'exit' in self.data.lower():
13
                    exit = True
14
                elif len(self.data) < 1:
15
                    continue
16
                else:
17
                    try:
18
                        # detect command
19
                        cmd = command[self.data]
20
                    except KeyError:
21
                        print 'Unkown Command %s' % self.data
22
                    else:
23
                        # call associated function if cmd was found.
24
                        cmd()
25
                        # tell client execution is done
26
                        self.request.sendall('Execution done')
27
        except Exception as e:
28
            print('Error : {}'.format(e))
29
30
31
def function1():
32
    print 'A is here'
33
34
def function2():
35
    print 'B is here'
36
37
if __name__ == "__main__":
38
    HOST, PORT = "", 9999
39
40
    SocketServer.TCPServer.allow_reuse_address = True
41
    # Create the server, binding to localhost on port 9999
42
    server = SocketServer.TCPServer((HOST, PORT), MyTCPHandler)
43
44
    # Activate the server; this will keep running until you
45
    # interrupt the program with Ctrl-C
46
    server.serve_forever()

das ist eigentlich nur das SocketServer example mit ein wenig 
Anpassungen im handle auf deine Bedürfnisse.

von imonbln (Gast)


Lesenswert?

Hier ist der handle nochmal ein wenig umgebaut, und entspricht etwas 
mehr dem was dein Code macht. Der Server macht nach jeden Befehl die 
Verbindung zu und kann mit Befehlen, wie dem oben erwähnten 'CAEE' 
umgehen. Wobei die for-schleife davon ausgeht das CAEE bedeutet führe C 
dann A, E, E aus.
1
    def handle(self):
2
        command = { 'A': function1,
3
                    'B': function2}
4
        exit = False
5
        try:
6
            self.data = self.request.recv(1024).strip()
7
            if len(self.data) > 1:
8
                for cur  in self.data:
9
                    try:
10
                        cmd = command[cur]
11
                    except KeyError:
12
                        print 'Unkown Command %s' % cur 
13
                    else:
14
                        cmd()
15
                        self.request.sendall('Execution done')
16
        except Exception as e:
17
            print('Error : {}'.format(e))

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.