first draft of pyPlcTcpSocket

This commit is contained in:
uhi22 2022-11-04 18:45:06 +01:00
parent 005263b672
commit 1d0c83839d
3 changed files with 165 additions and 44 deletions

3
.gitignore vendored
View file

@ -1,2 +1,3 @@
/__pycache__/ /__pycache__/
/doc/*.jar /doc/*.jar
*.bat

View file

@ -1,43 +0,0 @@
# explanation of socket handling:
# https://realpython.com/python-sockets/
#
import socket
import select
print("Press Ctrl-Break for aborting")
TCP_IP = 'fe80::e0ad:99ac:52eb:85d3'
TCP_PORT = 15118 # The port for CCS
BUFFER_SIZE = 1024 # Normally 1024
ourSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
ourSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
ourSocket.bind((TCP_IP, TCP_PORT))
ourSocket.listen(1)
print("listening on port " + str(TCP_PORT))
# example from https://stackoverflow.com/questions/5308080/python-socket-accept-nonblocking
read_list = [ourSocket]
while True:
# The select() function will block until one of the socket states has changed.
# We specify a timeout, to be able to run it in the main loop.
print("before select")
readable, writable, errored = select.select(read_list, [], [], 0.5)
for s in readable:
if s is ourSocket:
client_socket, address = ourSocket.accept()
read_list.append(client_socket)
print("Connection from", address)
else:
data = s.recv(1024)
if data:
print("received data:", data)
else:
print("connection closed")
s.close()
read_list.remove(s)

163
pyPlcTcpSocket.py Normal file
View file

@ -0,0 +1,163 @@
# Server on a non-blocking socket
#
# explanation of socket handling:
# https://docs.python.org/3/howto/sockets.html
# https://realpython.com/python-sockets/
# https://stackoverflow.com/questions/5308080/python-socket-accept-nonblocking
#
import socket
import select
import sys # for argv
import time # for time.sleep()
class pyPlcClientSocket():
def __init__(self):
self.sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
self.isConnected = False
def connect(self, host, port):
try:
self.sock.connect((host, port))
self.isConnected = True
except:
self.isConnected = False
def mysend(self, msg):
totalsent = 0
MSGLEN = len(msg)
while (totalsent < MSGLEN) and (self.isConnected):
try:
sent = self.sock.send(msg[totalsent:])
if sent == 0:
self.isConnected = False
raise RuntimeError("socket connection broken")
totalsent = totalsent + sent
except:
self.isConnected = False
def isRxDataAvailable(self):
# todo
# ... = self.sock.recv(..., 2048))
return 0
class pyPlcTcpServerSocket():
def __init__(self):
self.ipAdress = 'fe80::e0ad:99ac:52eb:85d3'
self.tcpPort = 15118 # The port for CCS
self.BUFFER_SIZE = 1024 # Normally 1024
# Concept explanation:
# We create a socket, that is just listening for incoming connections.
# Later in the cyclic loop, we use the "select" to wait for activity on this socket.
# In case there is a connection request, we create a NEW socket, which will handle the
# data exchange. The original socket is still listening for further incoming connections.
# This would allow to handle multiple connections.
self.ourSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
self.ourSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.ourSocket.bind((self.ipAdress, self.tcpPort))
self.ourSocket.listen(1)
print("pyPlcTcpSocket listening on port " + str(self.tcpPort))
self.read_list = [self.ourSocket]
self.rxData = []
def isRxDataAvailable(self):
return (len(self.rxData)>0)
def getRxData(self):
# provides the received data, and clears the receive buffer
d = self.rxData
self.rxData = []
return d
def transmit(self, txMessage):
numberOfSockets = len(self.read_list)
if (numberOfSockets!=2):
print("we have " + str(numberOfSockets) + ", we should have 2, one for accepting and one for data transfer. Will not transmit.")
return -1
totalsent = 0
MSGLEN = len(txMessage)
while totalsent < MSGLEN:
sent = self.read_list[1].send(txMessage[totalsent:])
if sent == 0:
print("socket connection broken")
return -1
totalsent = totalsent + sent
return 0
def mainfunction(self):
# The select() function will block until one of the socket states has changed.
# We specify a timeout, to be able to run it in the main loop.
# print("before select")
timeout_s = 0.05 # 50ms
readable, writable, errored = select.select(self.read_list, [], [], timeout_s)
for s in readable:
if s is self.ourSocket:
# We received a connection request at ourSocket.
# -> we create a new socket (named client_socket) for handling this connection.
client_socket, address = self.ourSocket.accept()
# and we append this new socket to the list of sockets, which in the next loop will be handled by the select.
self.read_list.append(client_socket)
print("Connection from", address)
else:
# It is not the "listener socket", it is an above created "client socket" for talking with a client.
# Let's take the data from it:
try:
data = s.recv(1024)
except:
# The client closed the connection in the meanwhile.
#print("The client closed the connection in the meanwhile.")
data = None
if data:
print("received data:", data)
self.rxData = data
else:
print("connection closed")
s.close()
self.read_list.remove(s)
def testServerSocket():
print("Testing the pyPlcTcpServerSocket...")
s = pyPlcTcpServerSocket()
print("Press Ctrl-Break for aborting")
nLoops = 0
while True:
s.mainfunction()
nLoops+=1
if ((nLoops % 10)==0):
print(str(nLoops) + " loops")
if (s.isRxDataAvailable()):
d = s.getRxData()
print("received " + str(d))
msg = "ok, you sent " + str(d)
s.transmit(bytes(msg, "utf-8"))
def testClientSocket():
print("Testing the pyPlcTcpClientSocket...")
c = pyPlcClientSocket()
c.connect('fe80::e0ad:99ac:52eb:85d3', 15118)
print("connected="+str(c.isConnected))
print("sending something to the server")
c.mysend(bytes("Test", "utf-8"))
print("waiting 3s")
time.sleep(3)
if (c.isRxDataAvailable()):
d = c.getRxData()
print("received " + str(d))
print("end")
if __name__ == "__main__":
if (len(sys.argv) == 1):
print("Use command line argument c for clientSocket or s for serverSocket")
exit()
if (sys.argv[1] == "c"):
testClientSocket()
exit()
if (sys.argv[1] == "s"):
testServerSocket()
exit()
print("Use command line argument c for clientSocket or s for serverSocket")