Erst einmal der Client, der ist eigentlich nichts besonderes und prinzipiell identisch mit dem was ich schon vor Jahren geschrieben hatte: Man muss Strg+C drücken, um etwas senden zu können. (Wenn ihr eine bessere Idee habt, wie man das lösen kann, ohne GUIs zu benutzen oder es sonstwie irre kompliziert zu machen, dann sprecht!)
Code: Alles auswählen
import socket
s = socket.socket()
print("--- halbwegs universeller Client ---")
ip = input("Server-IP eingeben: ")
port = int(input("Port: "))
nachricht = input("Anfangsnachricht (z.B. Nutzername): ") +"\n"
s.connect((ip,port))
s.send(nachricht.encode("utf-8"))
print("Mutmaßlich verbunden\n")
while True:
try:
msg = s.recv(1024)
except KeyboardInterrupt:
s.send((input("\t> ")+"\n").encode("utf-8"))
else:
print(msg.decode("utf-8"))
Code: Alles auswählen
#!/usr/bin/env python3
import asyncio
import datetime
verbindungsdict = dict()
verbindungslock = asyncio.Lock()
async def verbinden(rein, raus):
name = (await rein.readline()).decode("utf-8").strip()
async with verbindungslock:
if name not in verbindungsdict.keys():
verbindungsdict[name] = (rein, raus, raus.get_extra_info("peername"))
else:
return
await sende_an_alle("Verbunden mit: "+ name + str(raus.get_extra_info("peername")))
await asyncio.create_task(lesen(name, rein))
async def sende_an_alle(text):
text = datetime.datetime.now().strftime("%H:%M:%S") + " " + text
async with verbindungslock:
kopie = dict(verbindungsdict)
for v in kopie.values():
v[1].write(text.encode("utf-8"))
for v in kopie.values():
try:
await v[1].drain()
except ConnectionResetError:
print("Verbindung zurückgesetzt!")
print(text)
async def lesen(name, rein):
while True:
try:
text = await rein.readline()
except BrokenPipeError: # Verbindung verloren
async with verbindungslock:
del verbindungsdict[name]
await sende_an_alle("Verbindung verloren zu: "+ name)
return
text = name + ":\t" + text.decode("utf-8").strip()
await sende_an_alle(text)
async def main():
server = await asyncio.start_server(verbinden, "localhost", 25565) # das localhost muss ggf. geändert werden
addr = server.sockets[0].getsockname()
print("Servieren auf", addr)
async with server:
await server.serve_forever()
asyncio.run(main())
- Ist das vernünftig so, wie ich das mit dem Async mache?
- Ist das mit dem Lock vernünftig?
- Wie kann man die globalen Variablen eliminieren? Gibt es noch andere Möglichkeiten als eine Klasse zu schreiben?
- Hätte es eine Möglichkeit gegeben, direkt die Sockets aus dem sockets-Modul auf "asynchrone" Art zu benutzen, anstatt dieser Streams aus dem asyncio-Modul? Ich hatte das nämlich zunächst probiert, aber das Ergebnis war, dass ich mehr oder weniger mein altes gethreadetes Programm abgeschrieben habe aber mit "Tasks" statt Threads (und das fand ich dann sinnlos und habe es gelassen). Denn viel anders ging es nach meinem Dafürhalten nicht, da die ´recv´-Methode der Sockets sich eben die Zeit nimmt bis sie etwas hat (oder eine Exception wirft, je nachdem wie man das mit dem Timeout macht), und sich nicht "awaiten" lässt.
Jede Rückmeldung zu den Programmen ist willkommen.
Liebe Grüße