Hallo zusammen,
ich bin relativ unerfahren mit C#, muss trotzdem eine Anwendung programmieren. Im grossen und ganzen muss ich eine Art Gerätemanager programmieren, der Befehle von einem TCPIP Client entgegennimmt und diese beantwortet.
Der Gerätespezifische Teil bereitet mir keine Probleme, einen TCPIP Server habe ich bereits ebenfalls programmiert und ich kann von einem Client einfache Befehle schicken und antworten empfangen.
Nun kann man auf dem Gerät noch ein Programm starten. Der Start wird dem Client quittiert, soweit so gut. Nun verschickt das gerät, während das Programm läuft, noch laufend events. Bei jedem Event wird automatisch die Funktion RunProgramFunction() mit dem Status Parameter aufgerufen. In dieser Funktion möchte ich nun den jeweiligen Status ebenfalls an den Client senden. wie mache ich das, wenn die TCPIP Implementation in der Main() Klasse verwirklicht ist?
danke und gruss
Hier die (sehr) vereinfachten Klassen mit allen relevanten Codezeilen:
Program.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Threading;
namespace MyNamespace
{
static class Program
{
static int serverPort = 9999;
[STAThread]
static void Main()
{
TCPServerSocket();
}
private static void TCPServerSocket()
{
Instrument MeinInstrument = new Instrument();
Socket servSock = null;
string chrSTX = "\x02"; // Start of Text
string chrETX = "\x03"; // End of Text
try
{
// Verwende explizit IPv4
servSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Assoziiert den Socket mit einem lokalen Endpunkt
servSock.Bind(new IPEndPoint(IPAddress.Any, serverPort));
// Versetzt den Socket in den aktiven Abhörmodus
servSock.Listen(BACKLOG);
Console.WriteLine("Webserver running...");
}
catch (SocketException se)
{
Console.WriteLine(se.ErrorCode + ": " + se.Message);
Environment.Exit(se.ErrorCode);
}
byte[] rcvBuffer = new byte[BUFSIZE];
int bytesRcvd;
// Lässt den Server in einer Endlosschleife laufen
for (; ; )
{
Socket client = null;
try
{
client = servSock.Accept();
Console.WriteLine("Handling client at " + client.RemoteEndPoint + " - ");
// Empfange bis der client die Verbindung schließt, das geschieht indem 0
// zurückgegeben wird
int totalbytesEchoed = 0;
while ((bytesRcvd = client.Receive(rcvBuffer, 0, rcvBuffer.Length, SocketFlags.None)) > 0)
{
string cmd = System.Text.Encoding.Default.GetString(rcvBuffer, 0, bytesRcvd);
Console.WriteLine("-> {0}", cmd);
byte[] bufferToSend;
string reply = chrSTX + "OK" + chrETX;
switch (cmd)
{
case "CONNECT":
reply = chrSTX + MeinInstrument.Connect().ToString().ToUpper() + chrETX;
bufferToSend = Encoding.ASCII.GetBytes(reply);
client.Send(bufferToSend, 0, reply.Length, SocketFlags.None);
break;
case "DISCONNECT":
MeinInstrument.Disconnect();
bufferToSend = Encoding.ASCII.GetBytes("OK");
client.Send(bufferToSend, 0, reply.Length, SocketFlags.None);
break;
case "HEIZUNG_AN":
MeinInstrument.HeizungAn();
bufferToSend = Encoding.ASCII.GetBytes(reply);
client.Send(bufferToSend, 0, reply.Length, SocketFlags.None);
break;
case "HEIZUNG_AUS":
MeinInstrument.HeizungAus();
bufferToSend = Encoding.ASCII.GetBytes(reply);
client.Send(bufferToSend, 0, reply.Length, SocketFlags.None);
break;
case "RUN_PROGRAM":
MeinInstrument.RunProgram();
bufferToSend = Encoding.ASCII.GetBytes(reply);
client.Send(bufferToSend, 0, reply.Length, SocketFlags.None);
break;
default:
break;
}
totalbytesEchoed += reply.Length;
}
Console.WriteLine("echoed {0} bytes.", totalbytesEchoed);
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
client.Close();
}
}
}
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern bool AllocConsole();
private const int BUFSIZE = 32;
private const int BACKLOG = 5;
}
}
Instrument.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.IO;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace MyNamespace
{
public class Instrument
{
Socket servSock = null;
// Verwende explizit IPv4
/// <summary>
/// the constructor of the console class
/// </summary>
///
public Instrument()
{
}
public bool Connect()
{
return true;
}
public void Disconnect()
{
}
public int HeizungAn()
{
return 0;
}
public int HeizungAus()
{
return 0;
}
public int StartProgram()
{
// starte programm und exit
return 0;
}
/// <summary>
/// processes the status messages that are sent from the instrument
/// during a program is in progress.
/// Possible status of a started program.
/// Running: Program is running.
/// CycleNumber: Cycle number information
/// Finished: Program finished successfully.
/// Error: Program finished with an error.
/// Exception: A inner exception occurred.
/// Warning: A warning occured during program execution
private void RunProgramFunction(xyz status, object obj)
{
switch (status)
{
case ProgramStatus.Error:
// hier einen string via die im Hauptprogramm geöffnete TCPIP Verbindung senden
break;
case ProgramStatus.Finished:
// hier einen string via die im Hauptprogramm geöffnete TCPIP Verbindung senden
break;
case ProgramStatus.Running:
// hier einen string via die im Hauptprogramm geöffnete TCPIP Verbindung senden
break;
case ProgramStatus.Warning:
// hier einen string via die im Hauptprogramm geöffnete TCPIP Verbindung senden
break;
case ProgramStatus.Exception:
// hier einen string via die im Hauptprogramm geöffnete TCPIP Verbindung senden
break;
case ProgramStatus.CycleNumber:
// hier einen string via die im Hauptprogramm geöffnete TCPIP Verbindung senden
break;
default:
break;
}
}
}
}
Funktion RunProgramFunction()
Methode. Funktionen haben nur funktionale Programmiersprachen.
Zum Problem:
Ich sehe zwar nirgends eine Stelle, die RunProgramFunction aufgruft; aber natürlich muss an der Stelle die Verbindung zum Client bekannt sein.
Danach kannst Du über die Verbindung eben etwas an den Client schicken.
client.Send()
verwendest Du ja bereits an anderen Stellen.
PS: ich hoffe der Code ist nur für Dich; nicht für Kunden 😃
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
hinter dem Instrumenttreiber verbirgt sich noch eine ActiveX Bibliothek, da habe ich keinen Einfluss drauf. Kurz gesagt, beim Starten eines Programms, wird noch eben die Funktion RunProgramFunction() als Parameter mitgegeben, sodass es bekannt ist, welche Funktion bei einer Statusänderung auszuführen ist.
Wenn ich dort versuche client.Send() zu verwenden, wird die Stelle sofort unterstrichen mit der Info: The name 'client' does not exist in the current context
danke!
Wenn ich dort versuche client.Send() zu verwenden, wird die Stelle sofort unterstrichen mit der Info: The name 'client' does not exist in the current context
Natürlich brauchst Du an entsprechender Stelle das Client-Objekt. =)
Aber was wir Dir nicht abnehmen werden und halt auch nicht können ist, dass Du Dir ein paar Grundlagen aneignest.
Wir helfen hier bei konkreten Problemen: Hilfe zur Selbsthilfe; sind aber keine Lehrer, die Dir den Syntax beibringen 😉
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code