2016-07-15 12 views
0

Was die Absichten dieses Programms sind:Python Code nach Steckdosen Verbindung ausgeführt nur einmal

Ich mag einige Befehle von einem Client zu einem Server über Sockets senden, der Server dann diesen Befehl an einen Arduino mit serieller senden. Und eine andere Sache, die der Server in Zukunft tun soll, ist, dass er regelmäßig andere Befehle an den Arduino sendet, ohne dass er irgendwelche Eingaben vom Client erhält, also müssen die Sockets nicht blockierend sein oder es muss eine andere Möglichkeit geben, den Code auszuführen getrennt vom Socket-Code.

Das Problem ist, dass der Teil, der den Befehl an das Arduino senden soll, nur einmal ausgeführt wird.

Was ich nach dem Spielen mit dem Debugger in Pycharm herausgefunden habe, ist das Problem, dass die folgende Zeile blockiert, nachdem eine Verbindung hergestellt wurde, und damit den Rest des Codes nicht ausgeführt werden kann.

conn, addr = s.accept() 

Ist das korrekt, oder stimmt etwas anderes nicht?

Ich habe versucht, den Sockel nicht blockierend zu setzen, aber wenn ich dies tue, erhalte ich einen Fehler.

Ich habe ein paar Grundkenntnisse in C/C++ und C# und bin neu in Python.

server.py

import socket 
import serial 
import sys 
from _thread import * 
import threading 
import queue 

# command that the client sends are "ON" and "OFF" 

class serialConnect: 
    comPort =' ' 
    baudrate = 115200 
    myserial = serial.Serial('COM5', baudrate) 
    def serialstart(self): 
     # self.comPort = input('Comport: ') 
     try: 
      self.myserial.open() 
     except IOError: 
      print('Port is already open!') 

    def serialRead(self): 
     data = self.myserial.read(16) 
     data.decode('UTF-8') 
     return data 

    def serialWrite(self, data): 
     data += '\n'  #the arduino needs a \n after each command. 
     databytes = data.encode('UTF-8') 
     self.myserial.write(databytes) 
     print('send data: ', databytes) 


def threaded_client(conn, dataqueue): 
    data = {bytes} 
    conn.send(str.encode('welcome, type your info \n')) 
    while True: 
     data = conn.recv(2048) 
     if not data: 
      break 
     reply = 'server output: ' + data.decode('UTF-8') 
     dataqueue.put(data.decode('UTF-8')) 
     print("Items in queue: ",dataqueue.qsize()) 
     #conn.sendall(str.encode(reply)) 
     print("Recieved data in threaded_client: ", data.decode('UTF-8') + '\n') 

    conn.close() 

def Main(): 

    ser = serialConnect() 
    host = '' 
    port = 5555 
    dataRecieved = 'hello' 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    s.settimeout(2) 
    s.setblocking(1) #when set to non-blocking error occurs : "BlockingIOError: [WinError 10035] A non-blocking socket operation could not be completed immediately" 
    workQueue = queue.Queue(10) 

    try: 
     s.bind((host,port)) 
    except socket.error as e: 
     print(str(e)) 

    s.listen(5) 
    print('waiting for a connection') 

    while True: 
     try: 
      conn, addr = s.accept() #once connection is established it blocks? 
      print('connected to: ' + addr[0] + ':' + str()) 
      t = threading.Thread(target=threaded_client, args=(conn, workQueue)) 
      t.daemon = True 
      t.start() 

     except: 
      e = sys.exc_info() 
      print('Error:', e) 

     # This section of code is only run once, doesn't matter if put inside try block or not. :(
     dataRecieved = workQueue.get() 
     print('The recieved data: ', dataRecieved) 
     ser.serialstart() 
     ser.serialWrite(dataRecieved) 


if __name__ == '__main__': 
    Main() 

client.py

import socket 



def Main(): 
    host = '127.0.0.1' 
    port = 5555 

    message = "<,R,G,B,>" 
    mySocket = socket.socket() 
    mySocket.connect((host, port)) 

    while message != 'q': 
     message = input(" -> ") 
     mySocket.send(message.encode()) 
    mySocket.close() 




if __name__ == '__main__': 
    Main() 

Arduino-Code

String inputString = "";   // a string to hold incoming data 
boolean stringComplete = false; // whether the string is complete 

int LEDpin = 10; 
// the setup function runs once when you press reset or power the board 
void setup() { 
    // initialize digital pin 13 as an output. 
    pinMode(10, OUTPUT); 
    Serial.begin(19200); 
} 

// the loop function runs over and over again forever 
void loop() { 
    serialEvent(); 
    if(stringComplete){ 
    Serial.println(inputString); 
    if(inputString == "ON\n"){ 
     digitalWrite(LEDpin, HIGH); // turn the LED on (HIGH is the voltage level) 
     } 
    if(inputString == "OFF\n"){ 
     digitalWrite(LEDpin, LOW); // turn the LED off by making the voltage LOW 
     } 
    inputString = ""; 
    stringComplete = false; 
    } 
} 
void serialEvent() 
{ 
    while (Serial.available()) { 
    // get the new byte: 
    char inChar = (char)Serial.read(); 
    // add it to the inputString: 
    inputString += inChar; 
    // if the incoming character is a newline, set a flag 
    // so the main loop can do something about it: 
    if (inChar == '\n') { 
     stringComplete = true; 
    } 
    } 
} 
+0

Ihre Namenskonvention ist C# -Style. Python verwendet names_like_this für alles außer Klassen. Außerdem sollten Sie anstelle des expliziten '.close()' ' – Elazar

+0

' accept' * sollten * eine Anweisung 'with' verwenden, bis Sie eine Verbindung erhalten. Sobald Sie eine erste Verbindung akzeptieren, erstellt Ihr Code einen separaten Thread, der diese Verbindung verarbeitet, aber dann wird der Hauptthread (einmal) durch den Rest seiner Schleife laufen und dann erneut "accept" ausführen. Und so wird es blockieren, bis du * eine andere * Verbindung hast. Wenn das nicht der Fall ist, müssen Sie Ihren Code neu strukturieren. –

+0

Vielen Dank für Ihren Kommentar. Ich habe den Code überarbeitet und jetzt funktioniert es so, wie ich es möchte (zumindest jetzt). Siehe die Bearbeitung für den neuen Server-Code, der andere Code ist gleich geblieben. – MarkerDave

Antwort

2

Refactored-Servercode für alle, die daran interessiert sind.

Ich bin mir nicht sicher, ob dies dem Standard entspricht, aber es funktioniert.

import serial 
import socket 
import queue 
import sys 
import threading 

class serialConnect: 
    comPort = 'COM5' 
    baudrate = 115200 
    myserial = serial.Serial(comPort, baudrate) 

    def serial_run(self): 
     # self.comPort = input('Comport: ') 
     try: 
      if not self.myserial.isOpen(): 
       self.myserial.open() 
      else: 
       print('Port is already open!') 
     except IOError as e: 
      print('Error: ', e) 

    def serial_read(self): 
     data = self.myserial.read(16) 
     data.decode('UTF-8') 
     return data 

    def serial_write(self, data): 
     data += '\n'  #the arduino needs a \n after each command. 
     databytes = data.encode('UTF-8') 
     self.myserial.write(databytes) 
     print('send data: ', databytes) 


class socketServer: 
    host = '' 
    port = 5555 
    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    soc.setblocking(1) 
    data_queue = queue.Queue(1) 

    def __init__(self): 
     try: 
      self.soc.bind((self.host, self.port)) 
     except: 
      print('Bind error: ', sys.exc_info()) 
     self.soc.listen(5) 

    def socket_accept_thread(self): 
     while True: 
      try: 
       print('Waiting for a new connection') 
       conn, addr = self.soc.accept() 
       client_thread = threading.Thread(target=self.threaded_client, args=(conn, self.data_queue)) 
       client_thread.daemon = True 
       client_thread.start() 
      except: 
       print('Accept thread Error: ', sys.exc_info()) 

    def threaded_client(self, conn, data_queue): 
     # conn.send(str.encode('welcome, type your info \n')) 
     try: 
      while True: 
       data = conn.recv(2048) 
       if not data: 
        break 
       # reply = 'server output: ' + data.decode('UTF-8') 
       data_queue.put(data.decode('UTF-8')) 
       print("Items in queue: ", data_queue.qsize()) 
       # conn.sendall(str.encode(reply)) 
       print("Received data in threaded_client: ", data.decode('UTF-8')) 
     except: 
      print("Error: ", sys.exc_info()) 
     conn.close() 

    def get_data(self): 
     data = self.data_queue.get() 
     return data 


def Main(): 
    server = socketServer() 
    arduino_conn = serialConnect() 
    accept_thread = threading.Thread(target=server.socket_accept_thread) 

    data_received = 'Nothing received' 

    while True: 
     if not accept_thread.is_alive(): 
      accept_thread.daemon = True 
      accept_thread.start() 

     arduino_conn.serial_run() 
     data_received = server.get_data() 
     arduino_conn.serial_write(data_received) 

if __name__ == '__main__': 
    Main() 
Verwandte Themen