2016-10-28 1 views
1

Ich arbeite am UDP-Chat, der sollte zuhören und in der Lage sein, Nachricht jederzeit mit nur einem Sockel zu senden. Beispiel, ich werde das Chat-Programm fertig haben, ich werde es zum ersten Mal öffnen, dann zum zweiten Mal und ich muss in der Lage sein, über UDP von beiden Programmen zu kommunizieren, einfach hat jedes Programm nur einen geöffneten Socket.Mit einem Socket im UDP-Chat mit Threading

Meine zwei Threads sind zum Abhören, das ist Deamon-Thread, weil ich will, dass es neue Nachrichten nonstop hört, und mein anderer sendet die Nachrichten, die wie ein normaler Thread ist.

Zunächst ist mein Problem, dass es so aussieht, als ob meine Threads sich gegenseitig blockieren, denn wenn ich das Programm ausführe, bekomme ich nur die Ausgabe vom ersten Thread, den ich starte.

Das zweite Problem ist, dass ich nicht sicher bin, ob meine sendende Funktion oder die gesamte Klasse richtig geschrieben ist, oder ob etwas fehlt oder falsch ist.

Vielen Dank im Voraus. Übrigens, ich bin neu in Python und ich benutze Python 3, nur um es klar zu machen.

import socket 
import threading 
import logging 
import time 
from sys import byteorder 


class Sending(): 
    def __init__(self, name, tHost, tPort): 
     self.name = name 
     self.host = tHost 
     self.port = tPort 

    def set_name(self, name): 
     self.name = name 

    def send(self, name, tHost, tPort, msgType, dgramSize): 
     logging.debug('Starting send run') 
     message = input('Enter message: ') 
     data = bytearray() 
     data.extend((name.encode('utf-8'), message.encode('utf-8'), msgType.to_bytes(1, byteorder = 'little'))) 
     #data.extend(message.encode(encoding='utf_8')) 
     self.sock.sendto(bytearray(data), (tHost, tPort)) 

    def run(self): 

     th2 = threading.Thread(name = 'send', target=self.send('username', 'localhost', 8001, 1, 1400)) 
     th2.start() 

class Receiving(): 
    def __init__(self, host, port): 
     self.host = host 
     self.port = port 

    def create_socket(self, host, port): 
     logging.debug('Starting socket') 
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  
     sock.bind((host, port)) 
     #print ('socket ready') 
     time.sleep(5) 
     while True: 
      data, addr = sock.recvfrom(1500) 
      print('Prijata:' + data + addr) 

    def run(self): 

     th1 = threading.Thread(name = 'rec', target=self.create_socket('localhost', 8000)) 
     th1.setDaemon(True) 
     th1.start() 

if __name__ == '__main__': 
    #print ('running') 
    rec = Receiving('localhost', 8000) 
    send = Sending('username', 'localhost', 8001) 
    send.run() 
    rec.run()  

Antwort

0

Herzlichen Glückwunsch zu Ihrer Einführung in Python bedeuten! Es sieht so aus, als ob Sie Python 3 verwenden, und in zukünftigen Fragen ist es hilfreich, wenn Sie explizit angeben, welche Version Sie verwenden, da einige Code-Inkompatibilitäten (einschließlich dieses Codes!) Inkompatibel sind.

fand ich ein paar Fehler in Ihrem Programm:

  • Die wichtige Frage - wie Trevor Barnwell sagt, sie ist nicht threading.Thread ganz richtig fordern. Das Argument target= muss ein aufrufbares Objekt (d. H. Funktion) sein, aber in diesem Fall sollte es nur ein Verweis auf die Funktion sein. Wenn Sie der Funktion, wie oben beschrieben, self.create_socket(host, port) Klammern hinzufügen, wird die Funktion sofort ausgeführt. Wie Trevor erklärte, wurde Ihre Sending.send()-Methode früh aufgerufen, aber zusätzlich gab es einen ähnlichen Fehler in Receiving. Da Receiving.create_socket() eine Endlosschleife erstellt, gibt es nie die Programmausführung zurück. Während die Konsolenausgabe für den Benutzer korrekt aussieht, hat es die tatsächliche Programmausführung noch nie dazu gebracht, den Listener in einem separaten Thread auszuführen.

  • bytearray.extend() nimmt ein iterables von ints, was Sie gerade übergeben, ist ein Tupel von Byte-Objekten.

  • In Sending.send() rufen Sie self.sock, aber Sie vergeben nie self.sock einen Wert, so dass es fehlschlägt.

  • Sending.run() läuft nur einmal Sending.send() einmal. Nach Abschluss der Eingabe für den Benutzer wird dieser sofort beendet, da das Programm beendet wurde.

Wenn Sie sich für eine eingehende, projektbezogene Einführung in Python angemessen für einen erfahrenen Programmierer (einschließlich einer Übung sehr ähnlich wie diese Frage zu den grundlegenden Steckdosen, und ein anderes auf Threading) suchen, empfehle ich Sie sehen sich Wesley Chuns "Core Python Applications Programming" an. Die letzte Ausgabe (3rd) enthält viel Python 2-Code, ist aber leicht in Python 3 zu portieren.

Ich habe versucht, den Code so wenig wie möglich zu verändern es, hier ist es zum Laufen zu bringen:

import socket 
import threading 
import logging 
import time 


class Sending(): 
    def __init__(self, name, tHost, tPort, target): 
     self.name = name 
     self.host = tHost 
     self.port = tPort 
     self.target_port = target 
     self.sock = self.create_socket() 

    def create_socket(self): 
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
     sock.bind((self.host, self.port)) 
     return sock 

    def set_name(self, name): 
     self.name = name 

    def send_loop(self): 
     while True: 
      logging.debug('Starting send run') 
      message = input('Enter message: ') 
      data = bytearray() 
      data.extend(message.encode('utf-8')) 
      self.sock.sendto(bytearray(data), (self.host, self.target_port)) 

    def run(self): 
     th2 = threading.Thread(name='send', target=self.send_loop) 
     th2.start() 


class Receiving(): 
    def __init__(self, host, port): 
     self.host = host 
     self.port = port 

    def create_socket(self): 
     logging.debug('Starting socket') 
     sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
     sock.bind((self.host, self.port)) 
     print ('socket ready') 
     time.sleep(5) 
     while True: 
      data, addr = sock.recvfrom(1500) 
      print('\nPrijata:' + data.decode('utf-8') + str(addr)) 

    def run(self): 
     th1 = threading.Thread(name='rec', target=self.create_socket) 
     print("Made it here") 
     th1.daemon = True 
     th1.start() 
     return 

if __name__ == '__main__': 
    print('running') 
    rec = Receiving('localhost', 8000) 
    send = Sending('username', 'localhost', 8001, 8000) 
    rec.run() 
    send.run() 
+0

Und wenn ich das in zwei Konsolen auf meinem localhost ausführen möchte, wie soll ich dann die IP und den Port einstellen? Weil es in Ihrem Code einen Fehler gibt, dass nur eine Verwendung jeder Socket-Adresse erlaubt ist, aber ich habe dies durch Hinzufügen von 'sock.setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)' behoben und dann rec eingestellt Port auf '8000' und senden Ports beide '8001'. Führen Sie dann das Programm mit diesen Parametern aus und wechseln Sie dann die Ports: 'rec = 8001' und' send = 8000' für beide und öffnen Sie das Programm, so dass wir zwei Clients haben. Aber nur ein Client kann Nachrichten empfangen, andere können nur senden und nicht empfangen. – redesert17

+0

'sock.bind ((self.host, self.port))' in 'Senden' ist falsch. 'self.host' ist die entfernte Adresse, an die Sie keinen lokalen Socket binden können. – Barmar

0

Die Threads blockieren sich nicht gegenseitig. send wird aufgerufen, bevor ein Thread überhaupt erstellt wird.

th2 = threading.Thread(name = 'send', target=self.send('username', 'localhost', 8001, 1, 1400)) 

Diese Linie macht einen Aufruf senden an:

self.send('username', 'localhost', 8001, 1, 1400) 

Ich glaube, Sie, dies zu tun bedeutete:

th2 = threading.Thread(
    target=self.send 
    args=('username', 'localhost', 8001, 1, 1400)) 

Auf diese Weise wird ein Thread beginnen, dass Anrufe auf der nächsten senden Linie.

Zwei weitere Dinge:

  • Sie in Ihren Funktionen Schleife wollen, weil der Thread beendet wird, sobald die Funktion tut.
  • Ich glaube, Sie raw_input statt input
+0

Danke, jetzt weiß ich, was das 'args' für ist. – redesert17