Nun beschreibe ich, wie 2 Programme auf 2 verschiedenen Computern kommunizieren können.
Theoretisch könnten so auch 2 Programme auf demselben Computer kommunizieren, jedoch macht das nicht viel sinn, da andere Möglichkeiten für diesen Anwendungsfall bestehen.
Netzwerk-Kommunikation: TCP-Protokoll
Auch bei dieser Kommunikationsart braucht es eine Server-Applikation, welche die Daten empfängt und eine Client-Applikation, welche die Daten sendet.Server-Applikation
Um auch hier einen übersichtlicheren und besser wiederverwendbaren Code zu programmieren, habe ich eine Klasse erstellt und sie "Listener" genannt.Die Klasse hat 3 Klassenvariablen:
public TcpListener listener;
public delegate void dMessage(object sender, MessageEventArgs e);
public event dMessage Message;
Die Klasse TcpListener stellt den eigentlichen TCP-Listener bereit.
Das Delegate und der Event sind dazu da, um ein Event auszulösen, wenn eine Nachricht empfangen wurde.
Die Klasse MessageEventArgs, welche als Parameter verwendet wird ist identisch mit jener im Interprozesskommunikations-Beispiel und enthält lediglich einen public string der die gesendeten Daten übergeben soll:
public class MessageEventArgs
{
public MessageEventArgs(string message)
{
Message = message;
}
public string Message
{
set;
get;
}
}
Im Konstruktor der Listener-Klasse wird ein neuer Tcp-Listener instanziiert, jedoch wird er noch nicht verwendet.
Der TcpListener muss auf einen Port hören können. Daher wird ihm dieser als int übergeben.
public Listener(int port)
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
}
In einer eigenen Methode kann der TcpListener nun gestartet werden, damit er Daten empfangen kann.
Der Grund, weshalb der Server nicht direkt im Konstruktor gestartet wird ist, dass dieser somit in einen eigenen Thread ausgelagert werden kann und der Event im Objekt registriert werden kann, in dem es erstellt wurde.
Diese Start-Methode startet den Server bloss einmal, hört also bloss auf einen Client. Wenn dieser die Verbindung schliesst wird der Server beendet. Mit einer While-Schlaufe kann das ganze natürlich angepasst werden.
public void Start()
{
//Erstellt einen TCPListener, der auf den Port 4711 hört
//Startet den Listener
listener.Start();
//Wartet bis ein Client eine Verbindung aufbaut
TcpClient c = listener.AcceptTcpClient();
NetworkStream clientStream = c.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
//Wartet bis der Client Daten sendet
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//Fehler ist aufgetreten
break;
}
if (bytesRead == 0)
{
//Der Client hat die Verbindung geschlossen
break;
}
//Nachricht wurde empfangen
ASCIIEncoding encoder = new ASCIIEncoding();
//Löst das Message-Event mit dem gesendeten Inhalt als Message aus
Message(this, new MessageEventArgs(encoder.GetString(message, 0, bytesRead)));
}
//Verwirft den Client & Schliesst den Listener
c.Close();
listener.Stop();
}
Den Server kann man nun aus einer anderen Klasse z.B. so verwenden:
//Erstellt einen Listener der auf das Port 11993 hört
Listener tcpListener = new Listener(11993);
//Fängt das Message-Event des Listeners ab
tcpListener.Message += new Listener.dMessage(tcpListener_Message);
//Startet den Listener in einem neuen Thread
listener = new Thread(tcpListener.Start);
listener.Start();
Natürlich wird noch die Methode tcpListener_Message gebraucht, mit welcher wir in diesem Fall den Message-Event abarbeiten.
void tcpListener_Message(object sender, MessageEventArgs e)
{
//Nachricht verarbeiten
}
Client-Applikation
Bei der Client Applikation muss man eigentlich nur 2 Sachen beachten.1. Dass die richtige IP-Adresse als Ziel verwendet wird und 2. dass der selbe Port verwendet wird.
Auch hier habe ich wieder eine eigene Klasse Namens "Sender" erstellt.
Sie hat 1 Klassenvariablen:
private IPEndPoint serverEndPoint;
Die Klasse IPEndPoint stellt die Verbindungsdaten zum Server bereit und müssen daher nur 1 mal gesetzt werden.
Im Konstruktor der Sender-Klasse wird ein neuer IPEndPoint instanziiert.
Als Parameter werden die IP-Adresse des Servers und das passende Port übergeben.
public Sender(IPAddress ipAddress, int port)
{
serverEndPoint = new IPEndPoint(ipAddress, port);
}
In einer eigenen Methode können nun Nachrichten an den Server gesendet werden.
Als Parameter wird nur die Nachricht, welche gesendet werden soll übergeben.
public void Send(string message)
{
//Erstellt einen neuen TcpClient, der die Verbindung aufbauen
//und die Daten senden wird
TcpClient client = new TcpClient();
try
{
// Verbindung zum Server wird aufgebaut
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
try
{
//Codiert den String um, damit dieser gesendet werden kann
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(message);
//Schreibt die Nachricht in den Stream
clientStream.Write(buffer, 0, buffer.Length);
//Schickt die Nachricht
clientStream.Flush();
}
catch
{
//Fehler ist aufgetreten
MessageBox.Show("Nachricht konnte nicht gesendet werden");
}
//Schliesst die Verbindung zum Server
client.Close();
}
catch
{
//Verbindung konnte nicht aufgebaut werden
MessageBox.Show("Es konnte keine Verbindung Server hergestellt werden!");
}
}
Den Sender kann man nun so verwenden:
//Erstellt einen Sender der auf die Loopback-IP, also die
//IP des eigenen Computers und das Port 11993 sendet
Sender sender = new Sender(IPAddress.Parse("127.0.0.1", 11993);
//Sendet die Nachricht "Test";
sender.send("Test");
So kann immer wieder die Methode send aufgerufen werde um Daten zu senden.