I'm not quite sure why my application does not receive the message that is being sent to it. It appears the message is being sent. I looked at this example as reference.
how to listen to a specific port in qt using QTcpSocket?
I tried converting this c++ example as well and it didn't seem to send any messages as expected: QTcpSocket: reading and writing
The message being received should be printed to the console, however the bytes received always return 0.
import sys
from PyQt4 import QtNetwork, QtCore, QtGui
class Messenger(object):
def __init__(self):
super(Messenger, self).__init__()
self.TCP_HOST = '127.0.0.1' # QtNetwork.QHostAddress.LocalHost
self.TCP_SEND_TO_PORT = 7011
self.pSocket = None
self.listenServer = None
def slotSendMessage(self):
self.pSocket = QtNetwork.QTcpSocket();
self.pSocket.readyRead.connect(self.slotReadData)
self.pSocket.connectToHost(self.TCP_HOST, self.TCP_SEND_TO_PORT)
if not (self.pSocket.waitForConnected(1000)): # one second
print 'Unable to send data to port: "{}"'.format(self.TCP_SEND_TO_PORT)
return
cmd = "Hi there!"
print 'Command Sent:', cmd
ucmd = unicode(cmd, "utf-8")
self.pSocket.write(ucmd)
self.pSocket.waitForBytesWritten(1000)
# Do something with readData
self.pSocket.disconnectFromHost()
self.pSocket.waitForDisconnected(1000)
def slotReadData(self):
print 'Reading data:', self.pSocket.readAll()
# QByteArray data = pSocket->readAll();
class Client(QtCore.QObject):
def __init__(self, parent=None):
QtCore.QObject.__init__(self)
def SetSocket(self, Descriptor):
self.socket = QtNetwork.QTcpSocket(self)
self.connect(self.socket, QtCore.SIGNAL("connected()"), QtCore.SLOT(self.connected()))
self.connect(self.socket, QtCore.SIGNAL("disconnected()"), QtCore.SLOT(self.disconnected()))
self.connect(self.socket, QtCore.SIGNAL("readyRead()"), QtCore.SLOT(self.readyRead()))
self.socket.setSocketDescriptor(Descriptor)
print "Client Connected from IP %s" % self.socket.peerAddress().toString()
def connected(self):
print "Client Connected Event"
def disconnected(self):
print "Client Disconnected"
def readyRead(self):
msg = self.socket.readAll()
print type(msg), msg.count()
print "Client Message:", msg
class Server(QtCore.QObject):
def __init__(self, parent=None):
QtCore.QObject.__init__(self)
self.TCP_LISTEN_TO_PORT = 7011
def incomingConnection(self, handle):
print "Incoming Connection..."
self.client = Client(self)
self.client.SetSocket(handle)
def StartServer(self):
self.server = QtNetwork.QTcpServer()
self.server.incomingConnection = self.incomingConnection
if self.server.listen(QtNetwork.QHostAddress.Any, self.TCP_LISTEN_TO_PORT):
print "Server is listening on port: {}".format(self.TCP_LISTEN_TO_PORT)
else:
print "Server couldn't wake up"
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.setWindowTitle('TCP/Server')
self.resize(300, 300)
self.uiConnect =QtGui.QPushButton('Connect')
# layout
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.uiConnect)
self.widget = QtGui.QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
# Connections
self.uiConnect.clicked.connect(self.setup)
def setup(self):
server = Server()
server.StartServer()
tcp = Messenger()
tcp.slotSendMessage()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You make the following mistakes:
You should not use the waitForXXX methods since they are blocking, preventing the eventloop from executing and consequently the slots connected to the signals are not invoked.
It is not necessary to do self.server.incomingConnection = self.incomingConnection, it is like overwriting the class without using inheritance so you can generate problems, instead use the signal newConnection that indicates when there is a new connection and use nextPendingConnection() to get the socket.
Considering the above, the solution is:
import sys
from PyQt4 import QtCore, QtGui, QtNetwork
class Messenger(object):
def __init__(self):
super(Messenger, self).__init__()
self.TCP_HOST = "127.0.0.1" # QtNetwork.QHostAddress.LocalHost
self.TCP_SEND_TO_PORT = 7011
self.pSocket = None
self.listenServer = None
self.pSocket = QtNetwork.QTcpSocket()
self.pSocket.readyRead.connect(self.slotReadData)
self.pSocket.connected.connect(self.on_connected)
self.pSocket.error.connect(self.on_error)
def slotSendMessage(self):
self.pSocket.connectToHost(self.TCP_HOST, self.TCP_SEND_TO_PORT)
def on_error(self, error):
if error == QtNetwork.QAbstractSocket.ConnectionRefusedError:
print(
'Unable to send data to port: "{}"'.format(
self.TCP_SEND_TO_PORT
)
)
print("trying to reconnect")
QtCore.QTimer.singleShot(1000, self.slotSendMessage)
def on_connected(self):
cmd = "Hi there!"
print("Command Sent:", cmd)
ucmd = unicode(cmd, "utf-8")
self.pSocket.write(ucmd)
self.pSocket.flush()
self.pSocket.disconnectFromHost()
def slotReadData(self):
print("Reading data:", self.pSocket.readAll())
# QByteArray data = pSocket->readAll();
class Client(QtCore.QObject):
def SetSocket(self, socket):
self.socket = socket
self.socket.connected.connect(self.on_connected)
self.socket.disconnected.connect(self.on_connected)
self.socket.readyRead.connect(self.on_readyRead)
print(
"Client Connected from IP %s" % self.socket.peerAddress().toString()
)
def on_connected(self):
print("Client Connected Event")
def on_disconnected(self):
print("Client Disconnected")
def on_readyRead(self):
msg = self.socket.readAll()
print(type(msg), msg.count())
print("Client Message:", msg)
class Server(QtCore.QObject):
def __init__(self, parent=None):
QtCore.QObject.__init__(self)
self.TCP_LISTEN_TO_PORT = 7011
self.server = QtNetwork.QTcpServer()
self.server.newConnection.connect(self.on_newConnection)
def on_newConnection(self):
while self.server.hasPendingConnections():
print("Incoming Connection...")
self.client = Client(self)
self.client.SetSocket(self.server.nextPendingConnection())
def StartServer(self):
if self.server.listen(
QtNetwork.QHostAddress.Any, self.TCP_LISTEN_TO_PORT
):
print(
"Server is listening on port: {}".format(
self.TCP_LISTEN_TO_PORT
)
)
else:
print("Server couldn't wake up")
class Example(QtGui.QMainWindow):
def __init__(self):
super(Example, self).__init__()
self.setWindowTitle("TCP/Server")
self.resize(300, 300)
self.uiConnect = QtGui.QPushButton("Connect")
# layout
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.uiConnect)
self.widget = QtGui.QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
# Connections
self.uiConnect.clicked.connect(self.setup)
def setup(self):
self.server = Server()
self.server.StartServer()
self.tcp = Messenger()
self.tcp.slotSendMessage()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Related
I have an interface which has button for the read serial line.
class MainWindow(QMainWindow):
def __init__(self,parent = None):
QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
########################################################################
# APPLY JSON STYLESHEET
########################################################################
# self = QMainWindow class
# self.ui = Ui_MainWindow / user interface class
loadJsonStyle(self, self.ui)
########################################################################
QSizeGrip(self.ui.size_grip)
self.connection = SerialConnection()
self.Rs232 = RS232_Data()
self.ui.propertyListBtn.clicked.connect(self.get_property_list)
self.show()
def get_property_list(self):
self.Rs232.read(46,0,self.propertyDataArray) #Read Request
self.getAllByte = self.connection.serial_read_byte(236)
print(list(self.getAllByte))
# self.connection.connection_close()
#self.connection.connection_start()
This is the SerialConnection class:
import time
import serial
# serialPort = serial.Serial(port = "COM4", baudrate=115200,
# bytesize=8, timeout=2, stopbits=serial.STOPBITS_ONE)
import serial.tools.list_ports
class SerialConnection():
def __init__(self):
portList = serial.tools.list_ports.comports()
for p in portList:
if p.pid == 12345:
print("Confirmed")
self.getPortName = p.device
print(self.getPortName)
self.serialPort = serial.Serial(port=self.getPortName, baudrate=230400, bytesize=8, timeout=5,
stopbits=serial.STOPBITS_ONE)
break
else:
## Show dialog
print("There is no device on the line")
def connection_start(self):
try:
self.serialPort.open()
except Exception:
print("Port is already open")
def connection_close(self):
self.serialPort.close()
def serial_write(self, data):
self.data = data
self.serialPort.write(self.data)
def serial_read_string(self):
readData = self.serialPort.readline()
return readData
def serial_read_byte(self,size):
readData = self.serialPort.read(size)
return readData
RS232 Class:
class RS232_Data():
def __init__(self):
self.startOfTheFrame = "0x2621"
self.endOfTheFrame = "0x0D0A"
self.startOfTheFrameL = 0x26
self.startOfTheFrameH = 0x21
self.endOfTheFrameL = 0x0D
self.endOfTheFrameH = 0x0A
self.connection = SerialConnection()
def read(self,length,type,propertyData = []):
self.datagram = []
self.datagram.extend([startOfTheFrameL,startOfTheFrameH])
self.connection.serial_write(self.dataGram)
When I press the button only one time. I get correct value. But If I press second-three-third.. time I get wrong values.
But if I add below lines:
self.connection.connection_close()
self.connection.connection_start()
end of the get_property_list function, I get correct value everytime.
Is there any other way to do this? Do I have to close and open the connection every time?
In my case I have a texting app that has a receiver class that accepts incoming connections, and it has a pyqt signal connected to the main app class that will add messages to the screen upon being received. I want to be able to have two of these running and connect to eachother on different ports and send messages back and forth. This also means I want it to be able to run and listen for connections before itself connecting back.
I thought I'd create a connecter class, with the socket as a class variable, and then later instantiate that within the main app and link the send button pyqt signal to a send function that sends over that socket. It doesn't seem to like this. I get the error "socket.socket(socket.AF_INET, socket.SOCK_STREAM) as self.s" invalid syntax.
This is my code:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import socket
import numpy as np
from collections import deque, namedtuple
from threading import Thread
from time import sleep
HOST = '127.0.0.1'
inPORT = int(input('Input port to receive from: '))
outPORT = int(input('Input port to send to: '))
class Receiver(QThread):
received = pyqtSignal(object)
def __init__(self):
# self.outPORT = input('Input port to connect to: ')
super().__init__()
def run(self):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, inPORT))
s.listen()
print('Listening...')
conn, addr = s.accept()
with conn:
print('Connected by', addr)
while True:
data = conn.recv(1024)
self.received.emit(data)
class Connecter():
def __init__(self):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as self.c
self.c.connect((HOST, outPORT))
class ChatApp(QMainWindow):
def __init__(self):
super().__init__()
self.text_area = QTextEdit()
self.text_area.setReadOnly(True)
self.message_line = QLineEdit()
self.message_line.setFocus()
self.button = QPushButton('Send')
outerLayout = QVBoxLayout()
outerLayout.addWidget(self.text_area)
bottomLayout = QHBoxLayout()
bottomLayout.addWidget(self.message_line)
bottomLayout.addWidget(self.button)
outerLayout.addLayout(bottomLayout)
widget = QWidget()
widget.setLayout(outerLayout)
self.setWindowTitle("Chat App")
self.setWindowIcon(QIcon('ChatIcon.png'))
self.setCentralWidget(widget)
self.name = 'frd'
receiver = Receiver()
receiver.received.connect(self.addMessages)
self.threads = [receiver]
connecter = Connecter()
self.button.clicked.connect(self.sendMessage)
self.message_line.returnPressed.connect(self.sendMessage)
receiver.start()
# def askName(self):
# name, ask = QInputDialog.getText(self, 'input dialog', 'Enter username: ')
# return name
def sendMessage(self):
message = self.message_line.text()
connecter.c.sendall(message)
# headerArr = np.array([len(message)], dtype=np.uint16)
# header = headerArr.tobytes
def addMessages(self, message):
self.text_area.append(message.decode('utf-8'))
app = QApplication([])
myApp = ChatApp()
myApp.show()
app.exec()
The point of with is it creates something, then closes it again after the code inside the with is done. That doesn't apply here. It's not what you want the computer to do.
You can assign the socket to the variable like so:
self.c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
and when you are done with the socket, close it like so:
self.c.close()
Can you anyone please help me (noob) call the broadcast function from class BroadcastServerFactory in class process, as per attached code
I have tried so many methods of call a function from another class, but no solution
import time, sys
from apscheduler.scheduler import Scheduler
import threading
import socket
from twisted.internet import reactor
from twisted.python import log
from twisted.web.server import Site
from twisted.web.static import File
from autobahn.websocket import WebSocketServerFactory, \
WebSocketServerProtocol, \
listenWS
class process(threading.Thread):
def __init__(self, buffer3):
threading.Thread.__init__(self)
self.setDaemon(True)
self.buffer3 = buffer3
def run(self):
factory.broadcast("I don't know what I'm doing!")
class BroadcastServerProtocol(WebSocketServerProtocol):
def onOpen(self):
self.factory.register(self)
def onMessage(self, msg, binary):
if not binary:
self.factory.broadcast("'%s' from %s" % (msg, self.peerstr))
def connectionLost(self, reason):
WebSocketServerProtocol.connectionLost(self, reason)
self.factory.unregister(self)
class BroadcastServerFactory(WebSocketServerFactory):
"""
Simple broadcast server broadcasting any message it receives to all
currently connected clients.
"""
def __init__(self, url, debug = False, debugCodePaths = False):
WebSocketServerFactory.__init__(self, url, debug = debug, debugCodePaths = debugCodePaths)
self.clients = []
self.tickcount = 0
self.tick()
def tick(self):
self.tickcount += 1
self.broadcast("'tick %d' from server" % self.tickcount)
reactor.callLater(1, self.tick)
def register(self, client):
if not client in self.clients:
print "registered client " + client.peerstr
self.clients.append(client)
def unregister(self, client):
if client in self.clients:
print "unregistered client " + client.peerstr
self.clients.remove(client)
def broadcast(self, msg):
print "broadcasting message '%s' .." % msg
for c in self.clients:
c.sendMessage(msg)
print "message sent to " + c.peerstr
class BroadcastPreparedServerFactory(BroadcastServerFactory):
"""
Functionally same as above, but optimized broadcast using
prepareMessage and sendPreparedMessage.
"""
def broadcast(self, msg):
print "broadcasting prepared message '%s' .." % msg
preparedMsg = self.prepareMessage(msg)
for c in self.clients:
c.sendPreparedMessage(preparedMsg)
print "prepared message sent to " + c.peerstr
def testing():
buffer2 - "hello"
myDisplay = process(buffer2)
myDisplay.start()
if __name__ == '__main__':
if len(sys.argv) > 1 and sys.argv[1] == 'debug':
log.startLogging(sys.stdout)
debug = True
else:
debug = False
level_scheduler = Scheduler()
level_scheduler.add_interval_job(testing, seconds=5)
level_scheduler.start()
#ServerFactory = BroadcastServerFactory
ServerFactory = BroadcastPreparedServerFactory
factory = ServerFactory("ws://localhost:9000",
debug = debug,
debugCodePaths = debug)
factory.protocol = BroadcastServerProtocol
factory.setProtocolOptions(allowHixie76 = True)
listenWS(factory)
webdir = File(".")
web = Site(webdir)
reactor.listenTCP(8080, web)
reactor.run()
Thanks
Pass the class instance of BroadcastServerFactory to be called to the class instance that calls it process on creation
class process(threading.Thread):
def __init__(self, buffer3m, broadcast_server_factory):
threading.Thread.__init__(self)
self.setDaemon(True)
self.buffer3 = buffer3
self.factory = broadcast_server_factory
def run(self):
self.factory.broadcast("I don't know what I'm doing!")
and then call it (it's assigned as self.factory in the run statement. I can't see where you create a process class in your __main__ but it will be created with something like
p = process(buffer, factory)
Aside: Using capital letters for class names is considered good form in python process -> Process
I've been playing around with the Twisted extension and have fooled around with a chat room sort of system. However I want to expand upon it. As of now it only support multi-client chats with usernames ect. But I want to try and use the pyAudio extension to build a sort of VoIP application. I have a clientFactory and a simple echo protocol in the client and a serverFactory and protocol on the server. but I'm not entirely sure how to build off of this. What would be the best way to go about doing something like this?
Code to help if you need it
client.py:
import wx
from twisted.internet import wxreactor
wxreactor.install()
# import twisted reactor
import sys
from twisted.internet import reactor, protocol, task
from twisted.protocols import basic
class ChatFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, parent=None, title="WhiteNOISE")
self.protocol = None # twisted Protocol
sizer = wx.BoxSizer(wx.VERTICAL)
self.text = wx.TextCtrl(self, style=wx.TE_MULTILINE | wx.TE_READONLY)
self.ctrl = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER, size=(300, 25))
sizer.Add(self.text, 5, wx.EXPAND)
sizer.Add(self.ctrl, 0, wx.EXPAND)
self.SetSizer(sizer)
self.ctrl.Bind(wx.EVT_TEXT_ENTER, self.send)
def send(self, evt):
self.protocol.sendLine(str(self.ctrl.GetValue()))
self.ctrl.SetValue("")
class DataForwardingProtocol(basic.LineReceiver):
def __init__(self):
self.output = None
def dataReceived(self, data):
gui = self.factory.gui
gui.protocol = self
if gui:
val = gui.text.GetValue()
gui.text.SetValue(val + data)
gui.text.SetInsertionPointEnd()
def connectionMade(self):
self.output = self.factory.gui.text # redirect Twisted's output
class ChatFactory(protocol.ClientFactory):
def __init__(self, gui):
self.gui = gui
self.protocol = DataForwardingProtocol
def clientConnectionLost(self, transport, reason):
reactor.stop()
def clientConnectionFailed(self, transport, reason):
reactor.stop()
if __name__ == '__main__':
app = wx.App(False)
frame = ChatFrame()
frame.Show()
reactor.registerWxApp(app)
reactor.connectTCP("192.168.1.115", 5001, ChatFactory(frame))
reactor.run()
server.py:
from twisted.internet import reactor, protocol
from twisted.protocols import basic
import time
def t():
return "["+ time.strftime("%H:%M:%S") +"] "
class EchoProtocol(basic.LineReceiver):
name = "Unnamed"
def connectionMade(self):
#on client connection made
self.sendLine("WhiteNOISE")
self.sendLine("Enter A Username Below...")
self.sendLine("")
self.count = 0
self.factory.clients.append(self)
print t() + "+ Connection from: "+ self.transport.getPeer().host
def connectionLost(self, reason):
#on client connection lost
self.sendMsg("- %s left." % self.name)
print t() + "- Connection lost: "+ self.name
self.factory.clients.remove(self)
def lineReceived(self, line):
#actions to do on message recive
if line == '/quit':
#close client connection
self.sendLine("Goodbye.")
self.transport.loseConnection()
return
elif line == "/userlist":
#send user list to single client, the one who requested it
self.chatters()
return
elif line.startswith("/me"):
#send an action formatted message
self.sendLine("**" + self.name + ": " + line.replace("/me",""))
return
elif line == "/?":
self.sendLine("Commands: /? /me /userlist /quit")
return
if not self.count:
self.username(line)
else:
self.sendMsg(self.name +": " + line)
def username(self, line):
#check if username already in use
for x in self.factory.clients:
if x.name == line:
self.sendLine("This username is taken; please choose another")
return
self.name = line
self.chatters()
self.sendLine("You have been connected!")
self.sendLine("")
self.count += 1
self.sendMsg("+ %s joined." % self.name)
print '%s~ %s connected as: %s' % (t(), self.transport.getPeer().host, self.name)
def chatters(self):
x = len(self.factory.clients) - 1
s = 'is' if x == 1 else 'are'
p = 'person' if x == 1 else 'people'
self.sendLine("There %s %i other %s connected:" % (s, x, p) )
for client in self.factory.clients:
if client is not self:
self.sendLine(client.name)
self.sendLine("")
def sendMsg(self, message):
#send message to all clients
for client in self.factory.clients:
client.sendLine(t() + message)
class EchoServerFactory(protocol.ServerFactory):
protocol = EchoProtocol
clients = []
if __name__ == "__main__":
reactor.listenTCP(5001, EchoServerFactory())
reactor.run()
Take a look at Divmod Sine, a SIP application server. The basic idea is that you need an additional network server in your application that will support the VoIP parts of the application.
I modified the code (found here) a bit (added class AsyncEventLoop)
import socket,asyncore
import threading
class forwarder(asyncore.dispatcher):
def __init__(self, ip, port, remoteip,remoteport,backlog=5):
asyncore.dispatcher.__init__(self)
self.remoteip=remoteip
self.remoteport=remoteport
self.create_socket(socket.AF_INET,socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind((ip,port))
self.listen(backlog)
def handle_accept(self):
conn, addr = self.accept()
# print '--- Connect --- '
sender(receiver(conn),self.remoteip,self.remoteport)
def closef(self):
self.close()
class receiver(asyncore.dispatcher):
def __init__(self,conn):
asyncore.dispatcher.__init__(self,conn)
self.from_remote_buffer=''
self.to_remote_buffer=''
self.sender=None
def handle_connect(self):
pass
def handle_read(self):
read = self.recv(4096)
# print '%04i -->'%len(read)
self.from_remote_buffer += read
def writable(self):
return (len(self.to_remote_buffer) > 0)
def handle_write(self):
sent = self.send(self.to_remote_buffer)
# print '%04i <--'%sent
self.to_remote_buffer = self.to_remote_buffer[sent:]
def handle_close(self):
self.close()
if self.sender:
self.sender.close()
class sender(asyncore.dispatcher):
def __init__(self, receiver, remoteaddr,remoteport):
asyncore.dispatcher.__init__(self)
self.receiver=receiver
receiver.sender=self
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((remoteaddr, remoteport))
def handle_connect(self):
pass
def handle_read(self):
read = self.recv(4096)
# print '<-- %04i'%len(read)
self.receiver.to_remote_buffer += read
def writable(self):
return (len(self.receiver.from_remote_buffer) > 0)
def handle_write(self):
sent = self.send(self.receiver.from_remote_buffer)
# print '--> %04i'%sent
self.receiver.from_remote_buffer = self.receiver.from_remote_buffer[sent:]
def handle_close(self):
self.close()
self.receiver.close()
class AsyncEventLoop(threading.Thread):
def run(self):
asyncore.loop()
starting in the code
ser = forwarder('127.0.0.1', 7774, 'google.com.ua', 80)
evLoop = AsyncEventLoop()
Can I change remoteip, remoteport on the fly? If the fly is not possible to change, as well stop this thread to start with the new settings (remoteip, remoteport)?
yes, you can
ser.remoteip, ser.remoteport = IP, port