.NET-Client
In diesem Beispielprojekt wird gezeigt, wie unter .NET4.0 in C# ein Client für den SPS-TCP/IP-Server realisiert werden kann.

Das Beispiel nutzt die .NET-Bibliotheken System.Net und System.Net.Sockets, mit denen ein Programmierer ganz einfach Socket-Funktionen nutzen kann. Durch Drücken auf Enable versucht die Anwendung zyklisch (je nach dem Wert von TIMERTICK in [ms]) eine Verbindung zum Server herzustellen. Beim Erfolg kann ein String mit einer maximalen Länge von 255 Zeichen über den Send-Button zum Server gesendet werden. Dieser String wird dann vom Server angenommen und an den Client zurückgesendet. Die Verbindung wird serverseitig nach Ablauf der im Serverbeispiel definierten SERVER_RECEIVE_TIMEOUT -Zeit, default: 50 Sekunden, automatisch geschlossen, wenn der Server innerhalb dieser Zeit keine neue Daten vom Client empfangen konnte.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
/* ##########################################################################################
* This sample TCP/IP client connects to a TCP/IP-Server, sends a message and waits for the
* response. It is being delivered together with our TCP-Sample, which implements an echo server
* in PLC.
* ########################################################################################## */namespace TcpIpServer_SampleClient
{
publicpartialclassForm1 : Form
{
/* ##########################################################################################
* Constants
* ########################################################################################## */privateconstint RCVBUFFERSIZE = 256; // buffer size for receive bufferprivateconststring DEFAULTIP = "127.0.0.1";
privateconststring DEFAULTPORT = "200";
privateconstint TIMERTICK = 100;
/* ##########################################################################################
* Global variables
* ########################################################################################## */privatestaticbool _isConnected; // signals whether socket connection is active or notprivatestaticSocket _socket; // object used for socket connection to TCP/IP-ServerprivatestaticIPEndPoint _ipAddress; // contains IP address as entered in text fieldprivatestaticbyte[] _rcvBuffer; // receive buffer used for receiving response from TCP/IP-Serverpublic Form1()
{
InitializeComponent();
}
privatevoid Form1_Load(object sender, EventArgs e)
{
_rcvBuffer = newbyte[RCVBUFFERSIZE];
/* ##########################################################################################
* Prepare GUI
* ########################################################################################## */
cmd_send.Enabled = false;
cmd_enable.Enabled = true;
cmd_disable.Enabled = false;
rtb_rcvMsg.Enabled = false;
rtb_sendMsg.Enabled = false;
rtb_statMsg.Enabled = false;
txt_host.Text = DEFAULTIP;
txt_port.Text = DEFAULTPORT;
timer1.Enabled = false;
timer1.Interval = TIMERTICK;
_isConnected = false;
}
privatevoid cmd_enable_Click(object sender, EventArgs e)
{
/* ##########################################################################################
* Parse IP address in text field, start background timer and prepare GUI
* ########################################################################################## */try
{
_ipAddress = newIPEndPoint(IPAddress.Parse(txt_host.Text), Convert.ToInt32(txt_port.Text));
timer1.Enabled = true;
cmd_enable.Enabled = false;
cmd_disable.Enabled = true;
rtb_sendMsg.Enabled = true;
cmd_send.Enabled = true;
txt_host.Enabled = false;
txt_port.Enabled = false;
rtb_sendMsg.Focus();
}
catch (Exception ex)
{
MessageBox.Show("Could not parse entered IP address. Please check spelling and retry. " + ex);
}
}
/* ##########################################################################################
* Timer periodically checks for connection to TCP/IP-Server and reestablishes if not connected
* ########################################################################################## */privatevoid timer1_Tick(object sender, EventArgs e)
{
if (!_isConnected)
connect();
}
privatevoid connect()
{
/* ##########################################################################################
* Connect to TCP/IP-Server using the IP address specified in the text field
* ########################################################################################## */try
{
_socket = newSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
_socket.Connect(_ipAddress);
_isConnected = true;
if (_socket.Connected)
rtb_statMsg.AppendText(DateTime.Now.ToString() + ": Connectection to host established!\n");
else
rtb_statMsg.AppendText(DateTime.Now.ToString() + ": A connection to the host could not be established!\n");
}
catch (Exception ex)
{
MessageBox.Show("An error occured while establishing a connection to the server: " + ex);
}
}
privatevoid cmd_send_Click(object sender, EventArgs e)
{
/* ##########################################################################################
* Read message from text field and prepare send buffer, which is a byte[] array. The last
* character in the buffer needs to be a termination character, so that the TCP/IP-Server knows
* when the TCP stream ends. In this case, the termination character is '0'.
* ########################################################################################## */ASCIIEncoding enc = newASCIIEncoding();
byte[] tempBuffer = enc.GetBytes(rtb_sendMsg.Text);
byte[] sendBuffer = newbyte[tempBuffer.Length + 1];
for (int i = 0; i < tempBuffer.Length; i++)
sendBuffer[i] = tempBuffer[i];
sendBuffer[tempBuffer.Length] = 0;
/* ##########################################################################################
* Send buffer content via TCP/IP connection
* ########################################################################################## */try
{
int send = _socket.Send(sendBuffer);
if (send == 0)
thrownewException();
else
{
/* ##########################################################################################
* As the TCP/IP-Server returns a message, receive this message and store content in receive buffer.
* When message receive is complete, show the received message in text field.
* ########################################################################################## */
rtb_statMsg.AppendText(DateTime.Now.ToString() + ": Message successfully sent!\n");
IAsyncResult asynRes = _socket.BeginReceive(_rcvBuffer, 0, 256, SocketFlags.None, null, null);
if (asynRes.AsyncWaitHandle.WaitOne())
{
int res = _socket.EndReceive(asynRes);
char[] resChars = newchar[res + 1];
Decoder d = Encoding.UTF8.GetDecoder();
int charLength = d.GetChars(_rcvBuffer, 0, res, resChars, 0, true);
String result = newString(resChars);
rtb_rcvMsg.AppendText("\n" + DateTime.Now.ToString() + ": " + result);
rtb_sendMsg.Clear();
}
}
}
catch (Exception ex)
{
MessageBox.Show("An error occured while sending the message: " + ex);
}
}
privatevoid cmd_disable_Click(object sender, EventArgs e)
{
/* ##########################################################################################
* Disconnect from TCP/IP-Server, stop the timer and prepare GUI
* ########################################################################################## */
timer1.Enabled = false;
_socket.Disconnect(true);
if (!_socket.Connected)
{
_isConnected = false;
cmd_disable.Enabled = false;
cmd_enable.Enabled = true;
txt_host.Enabled = true;
txt_port.Enabled = true;
rtb_sendMsg.Enabled = false;
cmd_send.Enabled = false;
rtb_statMsg.AppendText(DateTime.Now.ToString() + ": Connectection to host closed!\n");
rtb_rcvMsg.Clear();
rtb_statMsg.Clear();
}
}
}
}