Socket-Programmierung ist eine wichtige Fähigkeit, welche ein Programmierer beherrschen sollte, da man damit seine Programme übers Internet kommunizieren lassen kann. Ein entsprechendes Modul, welches die nötigen Funktionen bereitstellt ist in fast jeder Programmiersprache Standard. Das Modul übernimmt dabei die Übersetzung in die darunterliegenden Soft- und Hardware Schichten. Man steigt dabei auf der UDP bzw. TCP Ebene ein.
Um eine Verbindung aufzubauen muss zunächst einmal ein Computer an einen Port bzw. seine IP gebunden werden und somit als Server definiert werden. Ist dies geschehen kann jeder andere Computer, welcher sich im gleichen Netzwerk befindet, sich mit dem Server verbinden, wenn dieser Port und IP kennt.

Aber jetzt genug mit der Theorie und auf zum praktischen Teil:
Eine beispielhafte Verbindung zwischen Client und Server in Python. Hierbei gibt der Server die IP des Clients zurück. Man kann ihn also verwenden um seine eigene IP herauszufinden ;).
Server:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#Import des "socket" -Moduls import socket #Socket-Objekt erzeugen sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #Server an eine IP-Adresse und Port binden sock.bind(("192.168.10.1", 20997)) #Starte Lauschen sock.listen(1) #nimmt den ersten Client an (Methode wartet bis ein Client kommt) client , addr = sock.accept() #Sende einen beliebigen Text client.sendall("""Willkommen auf dem Server, deine IP-Adresse lautet: """ + str(addr[0])) #Empfange die ersten 1024 bytes aus dem buffer #falls nichts im Buffer steht wartet der Interpreter print(recv(1024)) #Schließen der Verbindung client.close() |
Client:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#Import des "socket" -Moduls import socket #Socket-Objekt erzeugen sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #Mit einem Server mit der folgenden IP-Adresse und Port verbinden sock.connect(("192.168.10.1", 20997)) #Empfange die ersten 1024 bytes aus dem buffer #falls nichts im Buffer steht wartet der Interpreter print(recv(1024)) #Sende einen beliebigen Text sock.sendall("Danke jetzt kenne ich meine IP!") #Schließen der Verbindung sock.close() |
Und jetzt zu einem sehr einfachen Chat-Programm in Python. Zunächst wird die Funktionsweise von Client und Server an zwei Sequenzendiagrammen veranschaulicht.
- Server wird an einen Port und IP gebunden.
- Für jeden neuen Client wird ein „ClientObjekt“ als neuer Thread erzeugt.
- Das ClientObjekt leitet alle ankommenden Pakte an die anderen existierenden ClientObjekte weiter.
- Falls ein Client die Verbindung schließt, wird dies abgefangen.
- Verbindung zu einem Server mit bekanntem Port und IP
- Neuer Thread, welche auf Kommandozeileneingaben wartet und diese an den Server schickt
- ACHTUNG: Da bei der Python-Shell bei einem „input“ Befehl die komplette Shell blockiert wird und somit eingehende Chatnachrichten von Server nicht durch kommen, sollte das Programm auf der CMD gestartet werden.
- Die „checkBuffer()“ Methode printet eigehende Chatnachrichten an die Konsole
- Falls der Server die Verbindung schließt wird das Programm auch geschlossen.
Eigenprogrammiertes Chat-Programm:
Server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# -*- coding: utf-8 -*- #created by Tobias Jülg 28.11.2015 #server #imports import socket from threading import Thread from time import sleep import os #Konstanten: global slots slots=5 global host_ip host_ip= socket.gethostbyname(socket.gethostname()) global port port = 20997 class socketServer: "Klasse, welche den Server erstellt und nach Clienten lauscht" def __init__(self, ip, Port): "erstellt die Arrays mit größe 'slots' größe" self.clients=[0 for x in range(slots)] self.addr=[0 for x in range(slots)] self.slot=[0 for x in range(slots)] self.clients_rev=[0 for x in range(slots)] for i in range(len(self.slot)): self.slot[i]=0 self.host=ip self.port=Port print("SocketServer - IP: " + ip) print("SocketServer - PORT: " + str(Port)) self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.bind((host_ip, port)) print("SocketServer - " + str(slots) + " slots") print("SocketServer - " + "Waiting for clients...") self.listenForClients() #start listening def listenForClients(self): "Schleife welche nach Clients lauscht, für jeden neuen Client wird die Klasse connected geöffnet" try: while True: self.sock.listen(1) client , addr = self.sock.accept() for i in range(len(self.slot)): if self.slot[i]==0: self.slot[i]=1 test=True break else: test=False if test==True: self.clients[i] = client self.addr[i] = addr self.clients_rev[i]=connected(self, i) print("SocketServer - " + str(i+1) + "/" + str(slots) + " clients connected") else: print("SocketServer - Server is full") client.send(b'full') client.close() except KeyboardInterrupt: self.shutServerDown() print("SocketServer - " +"Server shutdown") sleep(1) os._exit(1) def shutServerDown(self): "schließt alle aktuellen Verbindungen" self.Listening=False for i in range(len(self.clients)): if self.slot[i]==1 and self.clients[i]!= None and self.clients[i]!=0: self.clients[i].close() class connected(Thread): "Für jeden neuen Client wird ein neues Objekt dieser Klasse erzeugt" def __init__(self, sockt, num): "Startet einen neuen Thread" self.num=num self.sockt=sockt print("SocketServer - " +'Connected with ' + str(self.sockt.addr[self.num])) Thread.__init__(self) self.start() def closeClient(self): "schließt den Client und gibt den Slot frei" print("SocketServer - " + str(self.sockt.addr[self.num]) + " disconnected") print("SocketServer - " + "Slot " + str(self.num) + " is now available") self.sockt.slot[self.num]=0 self.sockt.clients[self.num].close() self.sockt.clients[self.num] = None def send(self, text): "sendet den 'text' an den Client" self.sockt.clients[self.num].sendall(text)#ggf mit \n def recv(self): "gibt den Inhalt des Buffers zurück, falls nichts im Buffer steht wartet der Interpreter an dieser Stelle" return self.sockt.clients[self.num].recv(1024) def run(self): "Handshake und weiterleitung der ankommenden Packete an aller anderen verbundenen Clients" try: #handshake: if self.recv()!="Chat_certified_client": print(self.recv) self.sockt.clients[self.num].close() self.sockt.clients[self.num] = None print("SocketServer - " + str(self.sockt.addr[self.num]) + " not certified") print("SocketServer - " + "Slot " + str(self.num) + " is now available") self.sockt.slot[self.num]=0 return self.send("ok") except socket.error: self.closeClient() return print("SocketServer - " + "successful handshake") while True: try: textn = self.sockt.clients[self.num].recv(1024) if textn!=b'': for i in range(len(self.sockt.clients)): if i != self.num and self.sockt.slot[i]==1 and (self.sockt.clients[i]!=0 and self.sockt.clients[i]!=None): self.sockt.clients[i].sendall(textn) else: pass else: self.closeClient() break except socket.error: self.closeClient() break if __name__ =="__main__": s=socketServer(host_ip, port) #öffnet den Server |
Client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# -*- coding: cp1252 -*- #created by Tobias Jülg 28.11.2015 #client #imports: import socket from threading import Thread from time import sleep import os #Konstanten: global host_ip host_ip= "192.168.167.81" global port port = 20997 #name welcher im chat angezeigt wird global name name="Jobi" ############################################################## #Server_connection: ############################################################## class server_connection(Thread): def __init__(self, ip, Port): self.ip=ip self.port=Port print("(Client)" + 'TO: IP: ' + self.ip + '\n(Client)port: ' + str(self.port)) try: self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #socket Objekt self.server.connect((str(self.ip), int(self.port))) #verbungsaufbau zum Server print("(Client)" + "connected") #handshake self.server.sendall(b'Chat_certified_client') got=self.recv() if got=="full": print("(Client)" + "Server is full") self.close() elif got=="ok": print("(Client)" + "sucessfull handshake") Thread.__init__(self) self.start() self.inputSender() else: print("(Client)" + "unexpected Welcome msg") self.close() #falls die Verbindung abreißt oder keine möglich ist except socket.error: print("(Client)" + "Server is not online or wrong certificate") self.close() #schließt die Verbindung zum Server und beendet den Client def close(self): self.server.close() print("(Client)" + "PROGRAMM WIRD GESCHLOSSEN!") sleep(1) os._exit(1) #sendet text an den Server def send(self, text): self.server.sendall(text) #ließt den buffer auf neue strings vom server, es wird gewartet falls er leer ist def recv(self): return self.server.recv(1024) #Thread: warte auf neue strings vom server und printe sie def run(self): while True: try: text = self.recv() print("(Chat) " + text) except socket.error: print("(Client)" + "Server closed") self.close() #wartet auf einen input und schickt diesen an den server def inputSender(self): self.send(name + " joined the room") while True: try: toSend=raw_input("") if toSend!="": print("(Chat) You: " + str(toSend)) self.send(name + ": " + str(toSend)) except KeyboardInterrupt: print("(Client)" + "Close..") self.send(name + " left the room") self.close() except socket.error: print("(Client)" + "Server closed") self.close() if __name__ =="__main__": server_connection(host_ip, port) |