Keep in touch with your networking peers – make networking work for you

A very interesting article by Ali Hale at DumbLittleMan.com regarding how to make the most of your Network and ensure they know what you are doing all the time, you never know when you may need them!

One good point that is mentioned is:

In the long run, the people who you want to surround yourself with are people who like you for who you are, and who want to do business with the “real you”.

Another good idea is:

A large part of networking is simply letting people know what you’re up to. This could mean sending the occasional “newsletter” to old college friends; you never know who might be in need of your products or services. It also means taking the time to send out cards or even holiday gifts to your clients. Don’t keep trying to expand your network whilst neglecting or forgetting about those already in it.

More from the original article:
http://www.dumblittleman.com/2008/01/five-networking-tips-for-wallflowers.html

Client Socket Programming in C# using the built in libraries – a fully working production example Part 2

My previous article which you can find at http://blog.xploiter.com/index.php/2009/01/16/socket-programming-in-c-using-the-built-in-libraries-a-fully-working-production-example-part-1/ covered the creation of a solid production ready Socket Server written in C#. I promised to follow up with part 2 which would be a suitable client so without further ado, here we go:

App.Config

<?xml version=1.0 encoding=utf-8 ?>

<configuration>

<appSettings>

<add key=ServerIP value=127.0.0.1 />

<add key=ServerPort value=10001 />

</appSettings>

</configuration>

This time we define the server IP Address we wish to connect to as well as the port to use.

ExceptionHandler.CS

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data;

using System.Data.SqlClient;

using System.Windows;

namespace SocketClient

{

///

/// Handles displaying error messages

///

public class ExceptionHandler

{

///

/// Takes the exception message and displays a meaningful message to the user

///

public static string DisplayMessage(Exception ex)

{

return DisplayMessage(ex, “”);

}

///

/// Takes the exception message and displays a meaningful message to the user

///

/// The exception to display.

/// Current User

//[System.Diagnostics.DebuggerStepThrough()]

public static string DisplayMessage(Exception ex, string userName)

{

StringBuilder sb = new StringBuilder();

if (ex is DBConcurrencyException)

sb.Append(“Concurrency Error: One or more people have updated this data since your last request.”);

else if (ex is SqlException)

{

sb.Append(“Database Error: “);

switch (((SqlException)ex).Number)

{

case 547:

sb.Append(“There is a constraint on the items you tried to modify. Please try again.”);

break;

case 2601:

// Unique Index

sb.Append(“Cannot insert duplicate values into the database.”);

break;

case 2627:

// Unique Constraint

sb.Append(“Cannot insert duplicate values into the database.”);

break;

default:

sb.Append(ex.Message);

break;

}

}

else

{

sb.Append(“Exception Handler Unexpected Error: “ + ex.Message);

}

string nl = “nn”;

sb.Append(nl + “Exception Information:” + nl);

sb.Append(“Message: “ + ex.Message + nl);

sb.Append(“Source: “ + ex.Source + nl);

sb.Append(“Stack Trace: “ + ex.StackTrace + nl);

if (ex.InnerException != null)

{

sb.Append(nl + “Inner Exception Info:” + nl);

sb.Append(“Message: “ + ex.InnerException.Message + nl);

sb.Append(“Source: “ + ex.InnerException.Source + nl);

sb.Append(“Stack Trace: “ + ex.InnerException.StackTrace + nl);

}

return sb.ToString();

}

}

}

Same as the SocketServer code.

SocketClient.cs

using System;

using System.Windows.Forms;

using System.Net;

using System.Net.Sockets;

using System.Diagnostics;

using System.Collections;

using System.ComponentModel;

using System.Collections.Generic;

using System.Reflection;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Threading;

using System.IO;

using Microsoft.VisualBasic;

using System.Configuration;

namespace SocketClient

{

/// <summary>

/// Description of SocketClient.

/// </summary>

public class Client : System.Windows.Forms.Form

{

#region private members

byte[] m_dataBuffer = new byte[10];

IAsyncResult m_result;

public AsyncCallback m_pfnCallBack;

private System.Windows.Forms.Timer timerAlive;

private System.ComponentModel.IContainer components;

private int _ServerSocketID = 1;

public Socket m_clientSocket;

bool isClosing = false;

Int16 _Port = 10001; // default port we listen on

string _ServerIP = “127.0.0.1”;

private GroupBox groupBox1;

private Button buttonConnect;

private Button button1;

private TextBox textBoxMsg;

private Button buttonDisconnect;

private Button btnSendMessage;

private Label label4;

private RichTextBox richTextRxMessage;

private System.Windows.Forms.Timer tmrServerCheck;

// This delegate enables asynchronous calls for setting

// the text property on a TextBox control.

delegate void AppendTextCallback(string text);

delegate void DisconnectCallback();

#endregion private members

#region constructor

public Client()

{

//

// The InitializeComponent() call is required for Windows Forms designer support.

//

InitializeComponent();

_ServerIP = ConfigurationManager.AppSettings[“ServerIP”];

_Port = Convert.ToInt16(ConfigurationManager.AppSettings[“ServerPort”]);

}

[STAThread]

public static void Main(string[] args)

{

Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

Application.Run(new Client());

}

private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)

{

WriteToLogFile(ExceptionHandler.DisplayMessage(e.Exception));

MessageBox.Show(ExceptionHandler.DisplayMessage(e.Exception));

}

#endregion constructor

#region Windows Forms Designer generated code

/// <summary>

/// This method is required for Windows Forms designer support.

/// Do not change the method contents inside the source code editor. The Forms designer might

/// not be able to load this method if it was changed manually.

/// </summary>

private void InitializeComponent()

{

this.components = new System.ComponentModel.Container();

this.timerAlive = new System.Windows.Forms.Timer(this.components);

this.groupBox1 = new System.Windows.Forms.GroupBox();

this.buttonConnect = new System.Windows.Forms.Button();

this.button1 = new System.Windows.Forms.Button();

this.textBoxMsg = new System.Windows.Forms.TextBox();

this.buttonDisconnect = new System.Windows.Forms.Button();

this.btnSendMessage = new System.Windows.Forms.Button();

this.label4 = new System.Windows.Forms.Label();

this.richTextRxMessage = new System.Windows.Forms.RichTextBox();

this.tmrServerCheck = new System.Windows.Forms.Timer(this.components);

this.groupBox1.SuspendLayout();

this.SuspendLayout();

//

// timerAlive

//

this.timerAlive.Interval = 10000;

this.timerAlive.Tick += new System.EventHandler(this.timerAlive_Tick);

//

// groupBox1

//

this.groupBox1.Controls.Add(this.buttonConnect);

this.groupBox1.Controls.Add(this.button1);

this.groupBox1.Controls.Add(this.textBoxMsg);

this.groupBox1.Controls.Add(this.buttonDisconnect);

this.groupBox1.Controls.Add(this.btnSendMessage);

this.groupBox1.Controls.Add(this.label4);

this.groupBox1.Controls.Add(this.richTextRxMessage);

this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;

this.groupBox1.Location = new System.Drawing.Point(0, 0);

this.groupBox1.Name = “groupBox1”;

this.groupBox1.Size = new System.Drawing.Size(446, 159);

this.groupBox1.TabIndex = 18;

this.groupBox1.TabStop = false;

this.groupBox1.Text = “Client Setup”;

//

// buttonConnect

//

this.buttonConnect.BackColor = System.Drawing.SystemColors.HotTrack;

this.buttonConnect.Font = new System.Drawing.Font(“Tahoma”, 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

this.buttonConnect.ForeColor = System.Drawing.Color.Yellow;

this.buttonConnect.Location = new System.Drawing.Point(12, 19);

this.buttonConnect.Name = “buttonConnect”;

this.buttonConnect.Size = new System.Drawing.Size(85, 48);

this.buttonConnect.TabIndex = 38;

this.buttonConnect.Text = “Connect To Server”;

this.buttonConnect.UseVisualStyleBackColor = false;

this.buttonConnect.Click += new System.EventHandler(this.ButtonConnectClick);

//

// button1

//

this.button1.Location = new System.Drawing.Point(139, 124);

this.button1.Name = “button1”;

this.button1.Size = new System.Drawing.Size(49, 24);

this.button1.TabIndex = 35;

this.button1.Text = “Clear”;

this.button1.Click += new System.EventHandler(this.btnClear_Click);

//

// textBoxMsg

//

this.textBoxMsg.Location = new System.Drawing.Point(7, 98);

this.textBoxMsg.Name = “textBoxMsg”;

this.textBoxMsg.Size = new System.Drawing.Size(181, 20);

this.textBoxMsg.TabIndex = 33;

this.textBoxMsg.Tag = “”;

//

// buttonDisconnect

//

this.buttonDisconnect.BackColor = System.Drawing.Color.Red;

this.buttonDisconnect.Font = new System.Drawing.Font(“Tahoma”, 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

this.buttonDisconnect.ForeColor = System.Drawing.Color.Yellow;

this.buttonDisconnect.Location = new System.Drawing.Point(12, 19);

this.buttonDisconnect.Name = “buttonDisconnect”;

this.buttonDisconnect.Size = new System.Drawing.Size(85, 48);

this.buttonDisconnect.TabIndex = 32;

this.buttonDisconnect.Text = “Disconnect From Server”;

this.buttonDisconnect.UseVisualStyleBackColor = false;

this.buttonDisconnect.Visible = false;

this.buttonDisconnect.Click += new System.EventHandler(this.ButtonDisconnectClick);

//

// btnSendMessage

//

this.btnSendMessage.Enabled = false;

this.btnSendMessage.Location = new System.Drawing.Point(80, 124);

this.btnSendMessage.Name = “btnSendMessage”;

this.btnSendMessage.Size = new System.Drawing.Size(49, 24);

this.btnSendMessage.TabIndex = 31;

this.btnSendMessage.Text = “Send”;

this.btnSendMessage.Click += new System.EventHandler(this.ButtonSendMessageClick);

//

// label4

//

this.label4.Location = new System.Drawing.Point(9, 79);

this.label4.Name = “label4”;

this.label4.Size = new System.Drawing.Size(120, 16);

this.label4.TabIndex = 30;

this.label4.Text = “Message To Server”;

//

// richTextRxMessage

//

this.richTextRxMessage.BackColor = System.Drawing.SystemColors.InactiveCaptionText;

this.richTextRxMessage.Font = new System.Drawing.Font(“Microsoft Sans Serif”, 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

this.richTextRxMessage.Location = new System.Drawing.Point(194, 19);

this.richTextRxMessage.Name = “richTextRxMessage”;

this.richTextRxMessage.ReadOnly = true;

this.richTextRxMessage.Size = new System.Drawing.Size(247, 129);

this.richTextRxMessage.TabIndex = 27;

this.richTextRxMessage.Text = “”;

//

// tmrServerCheck

//

this.tmrServerCheck.Enabled = true;

this.tmrServerCheck.Interval = 5000;

this.tmrServerCheck.Tick += new System.EventHandler(this.tmrServerCheck_Tick);

//

// Client

//

this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);

this.ClientSize = new System.Drawing.Size(446, 159);

this.Controls.Add(this.groupBox1);

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;

this.Name = “Client”;

this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.SocketClient_FormClosed);

this.groupBox1.ResumeLayout(false);

this.groupBox1.PerformLayout();

this.ResumeLayout(false);

}

#endregion

#region event handlers

private void tmrServerCheck_Tick(object sender, EventArgs e)

{

// check to see if the server is available, if so connect to it automatically

// See if we have text on the IP and Port text fields

if (_ServerIP != “”)

{

try

{

UpdateControls(false);

CreateSocket();

UpdateControls(true);

buttonConnect.Visible = false;

buttonDisconnect.Visible = true;

btnSendMessage.Enabled = true;

}

catch (SocketException se)

{

WriteToLogFile(“Cannot connect to server, is it available?”);

UpdateControls(false);

}

}

}

void ButtonDisconnectClick(object sender, System.EventArgs e)

{

timerAlive.Enabled = false;

SendMessageToServer(“id=client,closing,socket=” + _ServerSocketID);

if (m_clientSocket != null)

{

m_clientSocket.Close();

m_clientSocket = null;

UpdateControls(false);

buttonConnect.Visible = true;

buttonDisconnect.Visible = false;

btnSendMessage.Enabled = false;

}

}

private void btnClear_Click(object sender, System.EventArgs e)

{

richTextRxMessage.Clear();

}

private void timerAlive_Tick(object sender, EventArgs e)

{

SendMessageToServer(“id=client,available,socket=” + _ServerSocketID);

}

private void ExitApplication()

{

ClosingApplication();

Close();

}

private void ClosingApplication()

{

SendMessageToServer(“id=client,shutdown,socket=” + _ServerSocketID);

isClosing = true;

if (m_clientSocket != null)

{

m_clientSocket.Close();

m_clientSocket = null;

}

}

private void SocketClient_FormClosed(object sender, FormClosedEventArgs e)

{

if (!isClosing)

ClosingApplication();

}

void ButtonConnectClick(object sender, System.EventArgs e)

{

// See if we have text on the IP and Port text fields

if (_ServerIP == “”)

{

MessageBox.Show(“Port Number is required to connect to the Servern”);

return;

}

try

{

UpdateControls(false);

CreateSocket();

UpdateControls(true);

buttonConnect.Visible = false;

buttonDisconnect.Visible = true;

btnSendMessage.Enabled = true;

}

catch (SocketException se)

{

string str;

str = “Connection failed, is the server running?n” + se.Message;

WriteToLogFile(str);

UpdateControls(false);

}

}

void ButtonSendMessageClick(object sender, System.EventArgs e)

{

SendMessageToServer(textBoxMsg.Text + “,socket=” + _ServerSocketID);

}

private void button1_Click(object sender, EventArgs e)

{

richTextRxMessage.Clear();

}

#endregion event handlers

#region private methods

// If the calling thread is different from the thread that

// created the TextBox control, this method creates a

// AppendTextCallback and calls itself asynchronously using the

// Invoke method.

//

// If the calling thread is the same as the thread that created

// the TextBox control, the Text property is set directly.

private void AppendRxText(string text)

{

// InvokeRequired required compares the thread ID of the

// calling thread to the thread ID of the creating thread.

// If these threads are different, it returns true.

if (this.richTextRxMessage.InvokeRequired)

{

AppendTextCallback d = new AppendTextCallback(AppendRxText);

this.Invoke(d, new object[] { text });

WriteToLogFile(text);

}

else

{

richTextRxMessage.AppendText(text + “r”);

WriteToLogFile(text);

}

}

private void ClosedownSocket()

{

if (this.buttonDisconnect.InvokeRequired)

{

DisconnectCallback d = new DisconnectCallback(ClosedownSocket);

this.Invoke(d, null);

}

else

this.ButtonDisconnectClick(this, null);

}

private void CreateSocket()

{

// Create the socket instance

m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

// Cet the remote IP address

IPAddress ip = IPAddress.Parse(_ServerIP);

int iPortNo = System.Convert.ToInt16(_Port);

// Create the end point

IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);

// Connect to the remote host

m_clientSocket.Connect(ipEnd);

if (m_clientSocket.Connected)

{

//Wait for data asynchronously

WaitForData();

}

}

/// <summary>

/// Allows us to send a string command to our server

/// </summary>

/// <param name=”msg”>string command to send (comma delimited format)</param>

private void SendMessageToServer(string msg)

{

try

{

if (m_clientSocket != null)

{

if (m_clientSocket.Connected)

{

// New code to send strings

NetworkStream networkStream = new NetworkStream(m_clientSocket);

System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);

streamWriter.WriteLine(msg);

streamWriter.Flush();

}

}

}

catch (SocketException se)

{

MessageBox.Show(se.Message);

}

}

/// <summary>

/// Allows us to send a Byte Array to our server

/// </summary>

/// <param name=”objData”>Byte array to send</param>

private void SendMessageToServer(byte[] objData)

{

try

{

// Use the following code to send bytes

byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());

if (m_clientSocket != null)

{

m_clientSocket.Send(byData);

}

}

catch (SocketException se)

{

MessageBox.Show(se.Message);

}

}

private void UpdateControls(bool connected)

{

buttonConnect.Enabled = !connected;

buttonDisconnect.Enabled = connected;

string connectStatus = connected ? “Connected” : “Not Connected”;

AppendRxText(connectStatus + “r”);

if (connected)

{

timerAlive.Enabled = true;

tmrServerCheck.Enabled = false;

}

else

{

timerAlive.Enabled = false;

tmrServerCheck.Enabled = true;

}

}

//—————————————————-

// This is a helper function used (for convenience) to

// get the IP address of the local machine

//—————————————————-

private String GetIP()

{

String strHostName = Dns.GetHostName();

// Find host by name

IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);

// Grab the first IP addresses

String IPStr = “”;

foreach (IPAddress ipaddress in iphostentry.AddressList)

{

IPStr = ipaddress.ToString();

return IPStr;

}

return IPStr;

}

private void Processcommand(string[] ClientCommand, SocketPacket socket)

{

// get our command string, parse it, pass through case statement

// and perform the relevant update i.e. label status

//int count = ClientCommand.Length; // how many elements in our array

if (ClientCommand[0].ToLower() != “server reply”)

{

switch (ClientCommand[0].ToLower())

{

case “shutdown”:

{

// server has closed the connection, ensure we disconnect

ClosedownSocket();

}

break;

case “servermsg:killclient”:

{

// shutdown this application

ClosedownSocket();

Close();

}

break;

case “hello”: // we have connected to our server, get our socketid to use in all our comms

// this ensures that our server knows which client has sent the command

{

string[] Args = SplitQuoted(ClientCommand[1], “trn”);

_ServerSocketID = Convert.ToInt32(Args[0]);

SendMessageToServer(“hello,” + _ServerSocketID + “,id=client”);

}

break;

default:

break;

}

}

}

/// <summary>

/// Here we decode the string sent from the client

/// </summary>

/// <param name=”szData”></param>

private string[] DecodeCommandString(string szData)

{

string[] command = SplitQuoted(szData, “;rn”);

return command;

}

private void WaitForData()

{

try

{

if (m_clientSocket != null)

{

if (m_pfnCallBack == null)

{

m_pfnCallBack = new AsyncCallback(OnDataReceived);

}

SocketPacket theSocPkt = new SocketPacket();

theSocPkt.thisSocket = m_clientSocket;

// Start listening to the data asynchronously

m_result = m_clientSocket.BeginReceive(theSocPkt.dataBuffer,

0, theSocPkt.dataBuffer.Length,

SocketFlags.None,

m_pfnCallBack,

theSocPkt);

WriteToLogFile(“Connected to “ + m_clientSocket.RemoteEndPoint.ToString());

}

}

catch (SocketException se)

{

MessageBox.Show(se.Message);

}

}

private void OnDataReceived(IAsyncResult asyn)

{

SocketPacket theSockId = (SocketPacket)asyn.AsyncState;

try

{

int iRx = theSockId.thisSocket.EndReceive(asyn);

char[] chars = new char[iRx + 1];

System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();

int charLen = d.GetChars(theSockId.dataBuffer, 0, iRx, chars, 0);

System.String szData = new System.String(chars);

string[] ClientCommand = SplitQuoted(szData, “,rn”);

Processcommand(ClientCommand, theSockId);

AppendRxText(szData + “r”);

WaitForData();

}

catch (ObjectDisposedException)

{

WriteToLogFile(“Socket has been closed”);

System.Diagnostics.Debugger.Log(0, “1”, “nOnDataReceived: Socket has been closedn”);

}

catch (SocketException se)

{

AppendRxText(se.Message + “: “ + theSockId.thisSocket.RemoteEndPoint);

if (se.Message == “An existing connection was forcibly closed by the remote host”)

{

WriteToLogFile(“Connection closed by remote host”);

ClosedownSocket();

}

else

MessageBox.Show(se.Message);

}

}

#endregion private methods

#region public methods

/// <summary>

/// Action to be performed by RetryOpen

/// </summary>

/// <returns></returns>

public delegate T RetryOpenDelegate<T>();

/// <summary>

/// Perform an action until succeeds without throwing IOException

/// </summary>

/// <typeparam name=”T”>object returned</typeparam>

/// <param name=”action”>action performed</param>

/// <returns></returns>

public static T RetryOpen<T>(RetryOpenDelegate<T> action)

{

while (true)

{

try

{

return action();

}

catch (IOException)

{

System.Threading.Thread.Sleep(50);

}

}

}

public static void WriteToLogFile(string msg)

{

// create our daily directory

string dir = Application.StartupPath + “\logs\” + DateTime.Now.ToString(“ddMMyyyy”);

if (!Directory.Exists(dir))

Directory.CreateDirectory(dir);

string LogFile = dir + “\” + DateTime.Now.ToString(“ddMMyyyy”) + “_Client_log.txt”;

TextWriter tw = null;

try

{

// create a writer and open the file

tw = RetryOpen<StreamWriter>(delegate()

{

return new StreamWriter(LogFile, true);

});

// write a line of text to the file

tw.WriteLine(DateTime.Now + “: ‘” + Environment.MachineName + “‘ – “ + msg);

}

catch { }

finally

{

// close the stream

if (tw != null)

{

tw.Close();

tw.Dispose();

}

}

}

/// <summary>

/// Splits any string using seperators string. This is different from the

/// string.Split method as we ignore delimiters inside double quotes and

/// will *ignore multiple delimiters in a row (i.e. “One,,,,two” will split

/// to two fields if comma is a delimiter).

/// Example:

/// Delims: ” t,” (space, tab, comma)

/// Input: “one two” three four,five

/// Returns (4 strings):

/// one two

/// three

/// four

/// five

/// </summary>

/// <param name=”text”>The string to split.</param>

/// <param name=”delimiters”>The characters to split on.</param>

/// <returns></returns>

public static string[] SplitQuoted(string text, string delimiters)

{

// Default delimiters are a space and tab (e.g. ” t”).

// All delimiters not inside quote pair are ignored.

// Default quotes pair is two double quotes ( e.g. ‘””‘ ).

if (text == null)

throw new ArgumentNullException(“text”, “text is null.”);

if (delimiters == null || delimiters.Length < 1)

delimiters = ” t”; // Default is a space and tab.

ArrayList res = new ArrayList();

// Build the pattern that searches for both quoted and unquoted elements

// notice that the quoted element is defined by group #2 (g1)

// and the unquoted element is defined by group #3 (g2).

string pattern =

@”””([^””\]*[\.[^””\]*]*)””” +

“|” +

@”([^” + delimiters + @”]+)”;

// Search the string.

foreach (System.Text.RegularExpressions.Match m in System.Text.RegularExpressions.Regex.Matches(text, pattern))

{

//string g0 = m.Groups[0].Value;

string g1 = m.Groups[1].Value;

string g2 = m.Groups[2].Value;

if (g2 != null && g2.Length > 0)

{

res.Add(g2);

}

else

{

// get the quoted string, but without the quotes in g1;

res.Add(g1);

}

}

return (string[])res.ToArray(typeof(string));

}

#endregion public methods

}

#region socketpacket class

public class SocketPacket

{

public System.Net.Sockets.Socket thisSocket;

public byte[] dataBuffer = new byte[1024];

}

#endregion socketpacket class

}

This is the main body of the application. Compile and run the code and at the same time have the server running.

The client will automatically try to connect to the server (see the timer code to see how) and once established send keep alive messages to let the server know it’s there. These will also be returned to the client and displayed accordingly.

Try sending some text, you will see it appear in the server and then be returned to the client.

Try this, add the following line into the text box on the client and send it:

showmessage,Hello from client

You should get a message box popup with your ‘Hello from client’ text.

That’s all there is to it. Simple eh!

Have fun and let me know if you make any modifications to improve it all

Si

Socket Programming in C# using the built in libraries – a fully working production example Part 1

One of the things i’ve noticed over the last few months in particular is the lack of decent programming examples in C# for a suitable client/server socket solution that just works! I was working on a contract that needed a robust and stable communications mechanism between multiple PC’s on a closed network for a Railway Simulator and Aircraft Simulator I was working on.

The following Server code is the first part of this two part article. It shows you how to code a solid and reliable server with error and message handling. Part two will explain how to code a client to go along with it.

Now i’m not naive enough to state there are no bugs in this code but it does work and work well. I would love to hear any comments from any developers that can help improve this code. The original code base I took from a couple of articles at the following URL’s, credit to the original authors:

http://www.developerfusion.co.uk/forums/p/36657/126609/#126609

http://www.codeguru.com/Csharp/Csharp/cs_network/sockets/article.php/c8781/

OK here goes, simply copy this code into the relevant files within a new solution. Bear in mind i’m using VS2008 here so you may need to modify the code accordingly for your environment. Should work fine in VS2005 with slight mods, not sure about VS2003

App.Config

<?xml version=1.0 encoding=utf-8 ?>

<configuration>

<appSettings>

<add key=ServerPort value=10001 />

</appSettings>

</configuration>

This defines the port that server will listen on.

Program.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Windows.Forms;

using System.Threading;

namespace SocketServer

{

static class Program

{

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);

Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

Application.Run(new Server());

}

private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)

{

Server.WriteToLogFile(ExceptionHandler.DisplayMessage(e.Exception));

MessageBox.Show(ExceptionHandler.DisplayMessage(e.Exception));

}

}

}

This is the starting point for the application. I’m also making use of the ExceptionHandler class I recently spoke about in my blog.

ExceptionHandler.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Data;

using System.Data.SqlClient;

using System.Windows;

namespace SocketServer

{

///

/// Handles displaying error messages

///

public class ExceptionHandler

{

///

/// Takes the exception message and displays a meaningful message to the user

///

public static string DisplayMessage(Exception ex)

{

return DisplayMessage(ex, “”);

}

///

/// Takes the exception message and displays a meaningful message to the user

///

/// The exception to display.

/// Current User

//[System.Diagnostics.DebuggerStepThrough()]

public static string DisplayMessage(Exception ex, string userName)

{

StringBuilder sb = new StringBuilder();

if (ex is DBConcurrencyException)

sb.Append(“Concurrency Error: One or more people have updated this data since your last request.”);

else if (ex is SqlException)

{

sb.Append(“Database Error: “);

switch (((SqlException)ex).Number)

{

case 547:

sb.Append(“There is a constraint on the items you tried to modify. Please try again.”);

break;

case 2601:

// Unique Index

sb.Append(“Cannot insert duplicate values into the database.”);

break;

case 2627:

// Unique Constraint

sb.Append(“Cannot insert duplicate values into the database.”);

break;

default:

sb.Append(ex.Message);

break;

}

}

else

{

sb.Append(“Exception Handler Unexpected Error: “ + ex.Message);

}

string nl = “nn”;

sb.Append(nl + “Exception Information:” + nl);

sb.Append(“Message: “ + ex.Message + nl);

sb.Append(“Source: “ + ex.Source + nl);

sb.Append(“Stack Trace: “ + ex.StackTrace + nl);

if (ex.InnerException != null)

{

sb.Append(nl + “Inner Exception Info:” + nl);

sb.Append(“Message: “ + ex.InnerException.Message + nl);

sb.Append(“Source: “ + ex.InnerException.Source + nl);

sb.Append(“Stack Trace: “ + ex.InnerException.StackTrace + nl);

}

return sb.ToString();

}

}

}

UtilityFunctions.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Net;

using System.Net.Sockets;

using System.Collections;

namespace SocketServer

{

class UtilityFunctions

{

public static String GetIP()

{

String strHostName = Dns.GetHostName();

// Find host by name

IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);

// Grab the first IP addresses

String IPStr = “”;

foreach (IPAddress ipaddress in iphostentry.AddressList)

{

IPStr = ipaddress.ToString();

return IPStr;

}

return IPStr;

}

/// <summary>

/// Splits any string using seperators string. This is different from the

/// string.Split method as we ignore delimiters inside double quotes and

/// will *ignore multiple delimiters in a row (i.e. “One,,,,two” will split

/// to two fields if comma is a delimiter).

/// Example:

/// Delims: ” t,” (space, tab, comma)

/// Input: “one two” three four,five

/// Returns (4 strings):

/// one two

/// three

/// four

/// five

/// </summary>

/// <param name=”text”>The string to split.</param>

/// <param name=”delimiters”>The characters to split on.</param>

/// <returns></returns>

public static string[] SplitQuoted(string text, string delimiters)

{

// Default delimiters are a space and tab (e.g. ” t”).

// All delimiters not inside quote pair are ignored.

// Default quotes pair is two double quotes ( e.g. ‘””‘ ).

if (text == null)

throw new ArgumentNullException(“text”, “text is null.”);

if (delimiters == null || delimiters.Length < 1)

delimiters = ” t”; // Default is a space and tab.

ArrayList res = new ArrayList();

// Build the pattern that searches for both quoted and unquoted elements

// notice that the quoted element is defined by group #2 (g1)

// and the unquoted element is defined by group #3 (g2).

string pattern =

@”””([^””\]*[\.[^””\]*]*)””” +

“|” +

@”([^” + delimiters + @”]+)”;

// Search the string.

foreach (System.Text.RegularExpressions.Match m in System.Text.RegularExpressions.Regex.Matches(text, pattern))

{

//string g0 = m.Groups[0].Value;

string g1 = m.Groups[1].Value;

string g2 = m.Groups[2].Value;

if (g2 != null && g2.Length > 0)

{

res.Add(g2);

}

else

{

// get the quoted string, but without the quotes in g1;

res.Add(g1);

}

}

return (string[])res.ToArray(typeof(string));

}

}

}

Just a couple of general routines we can call upon. I tend to add things like this to a separate class as it makes things nice and tidy.

SocketServer.Designer.cs

namespace SocketServer

{

partial class Server

{

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.IContainer components = null;

/// <summary>

/// Clean up any resources being used.

/// </summary>

/// <param name=”disposing”>true if managed resources should be disposed; otherwise, false.</param>

protected override void Dispose(bool disposing)

{

if (disposing && (components != null))

{

components.Dispose();

}

base.Dispose(disposing);

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support – do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

this.label1 = new System.Windows.Forms.Label();

this.groupBox1 = new System.Windows.Forms.GroupBox();

this.richTextBoxSendMsg = new System.Windows.Forms.RichTextBox();

this.btnClear = new System.Windows.Forms.Button();

this.richTextBoxReceivedMsg = new System.Windows.Forms.RichTextBox();

this.label8 = new System.Windows.Forms.Label();

this.buttonSendMsg = new System.Windows.Forms.Button();

this.groupBox1.SuspendLayout();

this.SuspendLayout();

//

// label1

//

this.label1.AutoSize = true;

this.label1.Font = new System.Drawing.Font(“Microsoft Sans Serif”, 11F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

this.label1.Location = new System.Drawing.Point(360, 9);

this.label1.Name = “label1”;

this.label1.Size = new System.Drawing.Size(115, 18);

this.label1.TabIndex = 7;

this.label1.Text = “Socket Server”;

//

// groupBox1

//

this.groupBox1.Controls.Add(this.richTextBoxSendMsg);

this.groupBox1.Controls.Add(this.label1);

this.groupBox1.Controls.Add(this.btnClear);

this.groupBox1.Controls.Add(this.richTextBoxReceivedMsg);

this.groupBox1.Controls.Add(this.label8);

this.groupBox1.Controls.Add(this.buttonSendMsg);

this.groupBox1.Dock = System.Windows.Forms.DockStyle.Fill;

this.groupBox1.Location = new System.Drawing.Point(0, 0);

this.groupBox1.Name = “groupBox1”;

this.groupBox1.Size = new System.Drawing.Size(477, 298);

this.groupBox1.TabIndex = 22;

this.groupBox1.TabStop = false;

//

// richTextBoxSendMsg

//

this.richTextBoxSendMsg.Location = new System.Drawing.Point(6, 27);

this.richTextBoxSendMsg.Name = “richTextBoxSendMsg”;

this.richTextBoxSendMsg.Size = new System.Drawing.Size(183, 21);

this.richTextBoxSendMsg.TabIndex = 45;

this.richTextBoxSendMsg.Text = “”;

//

// btnClear

//

this.btnClear.Location = new System.Drawing.Point(287, 27);

this.btnClear.Name = “btnClear”;

this.btnClear.Size = new System.Drawing.Size(88, 24);

this.btnClear.TabIndex = 43;

this.btnClear.Text = “Clear”;

this.btnClear.Click += new System.EventHandler(this.btnClear_Click);

//

// richTextBoxReceivedMsg

//

this.richTextBoxReceivedMsg.BackColor = System.Drawing.SystemColors.InactiveCaptionText;

this.richTextBoxReceivedMsg.Dock = System.Windows.Forms.DockStyle.Bottom;

this.richTextBoxReceivedMsg.Font = new System.Drawing.Font(“Microsoft Sans Serif”, 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));

this.richTextBoxReceivedMsg.Location = new System.Drawing.Point(3, 57);

this.richTextBoxReceivedMsg.Name = “richTextBoxReceivedMsg”;

this.richTextBoxReceivedMsg.ReadOnly = true;

this.richTextBoxReceivedMsg.Size = new System.Drawing.Size(471, 238);

this.richTextBoxReceivedMsg.TabIndex = 35;

this.richTextBoxReceivedMsg.Text = “”;

//

// label8

//

this.label8.Location = new System.Drawing.Point(3, 15);

this.label8.Name = “label8”;

this.label8.Size = new System.Drawing.Size(158, 20);

this.label8.TabIndex = 34;

this.label8.Text = “Broadcast Message To Clients”;

//

// buttonSendMsg

//

this.buttonSendMsg.Location = new System.Drawing.Point(192, 27);

this.buttonSendMsg.Name = “buttonSendMsg”;

this.buttonSendMsg.Size = new System.Drawing.Size(89, 24);

this.buttonSendMsg.TabIndex = 33;

this.buttonSendMsg.Text = “Send Message”;

this.buttonSendMsg.Click += new System.EventHandler(this.buttonSendMsg_Click);

//

// Server

//

this.AcceptButton = this.btnClear;

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

this.ClientSize = new System.Drawing.Size(477, 298);

this.Controls.Add(this.groupBox1);

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;

this.Name = “Server”;

this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;

this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;

this.Load += new System.EventHandler(this.LaunchForm_Load);

this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Server_FormClosed);

this.groupBox1.ResumeLayout(false);

this.groupBox1.PerformLayout();

this.ResumeLayout(false);

}

#endregion

private System.Windows.Forms.Label label1;

private System.Windows.Forms.GroupBox groupBox1;

private System.Windows.Forms.Button btnClear;

private System.Windows.Forms.RichTextBox richTextBoxReceivedMsg;

private System.Windows.Forms.Label label8;

private System.Windows.Forms.Button buttonSendMsg;

private System.Windows.Forms.RichTextBox richTextBoxSendMsg;

}

}

SocketServer.cs

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.Diagnostics;

using System.Threading;

using System.IO;

using System.Net;

using System.Net.Sockets;

using System.Collections;

using System.Reflection;

using System.Configuration;

namespace SocketServer

{

public partial class Server : Form

{

#region socket stuff

// sample code and basis of client/server app taken from the following url’s

// http://www.developerfusion.co.uk/forums/p/36657/126609/#126609

// http://www.codeguru.com/Csharp/Csharp/cs_network/sockets/article.php/c8781/

public delegate void UpdateRichEditCallback(string text);

public delegate void UpdateClientListCallback();

public AsyncCallback pfnWorkerCallBack;

private Socket m_mainSocket;

// An ArrayList is used to keep track of worker sockets that are designed

// to communicate with each connected client. Make it a synchronized ArrayList

// For thread safety

private System.Collections.ArrayList m_workerSocketList = ArrayList.Synchronized(new System.Collections.ArrayList());

// This delegate enables asynchronous calls for setting

// the text property on a TextBox control.

delegate void AppendTextCallback(string text);

// The following variable will keep track of the cumulative

// total number of clients connected at any time. Since multiple threads

// can access this variable, modifying this variable should be done

// in a thread safe manner

private int m_clientCount = 0;

Dictionary<string, int> SocketMachineID = new Dictionary<string, int>(); // int = socketid, string = machineid

#endregion socket stuff

#region private members

Int16 _Port = 10001; // default port we listen on

bool isClosing = false;

byte[] m_dataBuffer = new byte[10];

public AsyncCallback m_pfnCallBack;

public Socket m_clientSocket;

#endregion

#region constructor

public Server()

{

InitializeComponent();

_Port = Convert.ToInt16(ConfigurationManager.AppSettings[“ServerPort”]);

}

#endregion constructor

#region private methods

/// <summary>

/// Search our dictionary to get the index of our socket to send the correct data down

/// </summary>

/// <param name=”Mode”>Client mode, we can identify our individual clients here, I will use Client for this example</param>

/// <returns>Integer contaning the socket id to pass into SendMsgToClient method</returns>

private int GetModeFromDictionary(string Mode)

{

int value = 1;

SocketMachineID.TryGetValue(Mode, out value);

return value;

}

#endregion private methods

#region event handlers

/// <summary>

/// Action to be performed by RetryOpen

/// </summary>

/// <returns></returns>

public delegate T RetryOpenDelegate<T>();

/// <summary>

/// Perform an action until succeeds without throwing IOException

/// </summary>

/// <typeparam name=”T”>object returned</typeparam>

/// <param name=”action”>action performed</param>

/// <returns></returns>

public static T RetryOpen<T>(RetryOpenDelegate<T> action)

{

while (true)

{

try

{

return action();

}

catch (IOException)

{

System.Threading.Thread.Sleep(50);

}

}

}

public static void WriteToLogFile(string msg)

{

// create our daily directory

string dir = Application.StartupPath + “\logs\” + DateTime.Now.ToString(“ddMMyyyy”);

if (!Directory.Exists(dir))

Directory.CreateDirectory(dir);

string LogFile = dir + “\” + DateTime.Now.ToString(“ddMMyyyy”) + “_Server_log.txt”;

TextWriter tw = null;

try

{

// create a writer and open the file

tw = RetryOpen<StreamWriter>(delegate()

{

return new StreamWriter(LogFile, true);

});

// write a line of text to the file

tw.WriteLine(DateTime.Now + “: ‘” + Environment.MachineName + “‘ – “ + msg);

}

catch { }

finally

{

// close the stream

if (tw != null)

{

tw.Close();

tw.Dispose();

}

}

}

private void buttonSendMsg_Click(object sender, EventArgs e)

{

AppendToRichEditControl(“User Sending Message :” + richTextBoxSendMsg.Text);

SendMsgToAllClients(richTextBoxSendMsg.Text);

}

private void btnClear_Click(object sender, EventArgs e)

{

richTextBoxReceivedMsg.Clear();

}

void ExitApplication()

{

isClosing = true;

SendMsgToClient(“Shutdown”, 1); // broadcast message to all clients

Close();

}

private void Server_FormClosed(object sender, FormClosedEventArgs e)

{

if (!isClosing)

CloseSockets();

}

private void LaunchForm_Load(object sender, EventArgs e)

{

StartServerListening(); //Ensure our clients can find us by starting the server running

}

#endregion event handlers

#region Socket Methods

private void StartServerListening()

{

try

{

// Create the listening socket…

m_mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, _Port);

// Bind to local IP Address…

m_mainSocket.Bind(ipLocal);

// Start listening – allow 5 simultaneous connections…

m_mainSocket.Listen(5);

// Create the call back for any client connections…

m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);

}

catch (SocketException se)

{

AppendToRichEditControl(se.Message);

}

}

/// <summary>

/// This is the call back function, which will be invoked when a client is connected

/// </summary>

/// <param name=”asyn”></param>

public void OnClientConnect(IAsyncResult asyn)

{

try

{

if (m_mainSocket != null)

{

// Here we complete/end the BeginAccept() asynchronous call

// by calling EndAccept() – which returns the reference to a new Socket object

Socket workerSocket = m_mainSocket.EndAccept(asyn);

// Now increment the client count for this client in a thread safe manner

Interlocked.Increment(ref m_clientCount);

// Add the workerSocket reference to our ArrayList

m_workerSocketList.Add(workerSocket);

// Send a welcome message to client with their socket id so they can communicate properly with us

string msg = “hello,” + m_clientCount;

SendMsgToClient(msg, m_clientCount);

// Let the worker Socket do the further processing for the just connected client

WaitForData(workerSocket, m_clientCount);

// Since the main Socket is now free, it can go back and wait for

// other clients who are attempting to connect

m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);

}

}

catch (ObjectDisposedException)

{

System.Diagnostics.Debugger.Log(0, “1”, “n OnClientConnection: Socket has been closedn”);

}

catch (SocketException se)

{

AppendToRichEditControl(se.Message);

}

}

/// <summary>

/// Start waiting for data from the client

/// </summary>

/// <param name=”soc”></param>

/// <param name=”clientNumber”></param>

public void WaitForData(System.Net.Sockets.Socket soc, int clientNumber)

{

try

{

if (pfnWorkerCallBack == null)

{

// Specify the call back function which is to be

// invoked when there is any write activity by the connected client

pfnWorkerCallBack = new AsyncCallback(OnDataReceived);

}

SocketPacket theSocPkt = new SocketPacket(soc, clientNumber);

soc.BeginReceive(theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, pfnWorkerCallBack, theSocPkt);

AppendToRichEditControl(“Connected to Client “ + soc.RemoteEndPoint);

}

catch (SocketException se)

{

AppendToRichEditControl(se.Message);

}

}

/// <summary>

/// This the call back function which will be invoked when the socket

/// detects any client writing of data on the stream

/// </summary>

/// <param name=”asyn”></param>

public void OnDataReceived(IAsyncResult asyn)

{

SocketPacket socketData = (SocketPacket)asyn.AsyncState;

try

{

// Complete the BeginReceive() asynchronous call by EndReceive() method

// which will return the number of characters written to the stream by the client

int iRx = socketData.m_currentSocket.EndReceive(asyn);

char[] chars = new char[iRx + 1];

// Extract the characters as a buffer

System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();

int charLen = d.GetChars(socketData.dataBuffer, 0, iRx, chars, 0);

System.String szData = new System.String(chars);

string msg = “” + socketData.m_clientNumber + “:”;

Processcommand(DecodeCommandString(szData), socketData);

AppendToRichEditControl(msg + szData);

msg = “command=” + Dns.GetHostName() + “,ok,” + szData;

SendMsgToClient(msg, socketData); // send our response back to the calling client

// Continue the waiting for data on the Socket

WaitForData(socketData.m_currentSocket, socketData.m_clientNumber);

}

catch (ObjectDisposedException)

{

System.Diagnostics.Debugger.Log(0, “1”, “nOnDataReceived: Socket has been closedn”);

}

catch (SocketException se)

{

if (se.ErrorCode == 10054) // Error code for Connection reset by peer

{

string msg = “Client “ + socketData.m_clientNumber + ” Disconnected” + “n”;

AppendToRichEditControl(msg);

// Remove the reference to the worker socket of the closed client

// so that this object will get garbage collected

m_workerSocketList[socketData.m_clientNumber 1] = null;

}

else

{

MessageBox.Show(“SocketException Error in OnDataReceived: “ + se.Message + “r” + se.StackTrace);

}

}

catch (Exception ex)

{

MessageBox.Show(“General Error in OnDataReceived: “ + ex.Message + “r” + ex.StackTrace);

}

}

private void Processcommand(string[] ClientCommand, SocketPacket socket)

{

// get our command string, parse it, pass through case statement

// and perform the relevant update i.e. label status

int count = ClientCommand.Length; // how many elements in our array

for (int i = 0; i < count; i++)

{

switch (ClientCommand[0].ToLower())

{

case “hello”: // hello from client

{

int SocketID = Convert.ToInt16(ClientCommand[1]); // get our socket

string Ident = “”;

if (ClientCommand[2].ToLower() == “id”)

Ident = ClientCommand[3];

// check if key already exists

if (!SocketMachineID.ContainsKey(Ident))

{

try

{

// Now add to dictionary

SocketMachineID.Add(Ident, SocketID);

}

catch (ArgumentException)

{

SocketMachineID.Remove(Ident); // remove the invalid entry

SocketMachineID.Add(Ident, SocketID); // re-add it

AppendToRichEditControl(“Updated key in dictionary”);

}

}

}

break;

case “id”: // machine identifier

{

if (ClientCommand[1].ToLower() == “client”)

{

bool avail = ClientCommand[2].ToLower() == “available”;

}

}

break;

case “showmessage”:

{

MessageBox.Show(ClientCommand[1]);

}

break;

default:

break;

}

}

}

/// <summary>

/// Here we decode the string sent from the client

/// </summary>

/// <param name=”szData”></param>

private string[] DecodeCommandString(string szData)

{

string[] command = UtilityFunctions.SplitQuoted(szData, “=,rn”);

return command;

}

/// <summary>

/// This method could be called by either the main thread or any of the worker threads

/// </summary>

/// <param name=”msg”>String to append</param>

private void AppendToRichEditControl(string msg)

{

// Check to see if this method is called from a thread other than the one created the control

if (InvokeRequired)

{

// We cannot update the GUI on this thread.

// All GUI controls are to be updated by the main (GUI) thread.

// Hence we will use the invoke method on the control which will

// be called when the Main thread is free

// Do UI update on UI thread

object[] pList = { msg };

richTextBoxReceivedMsg.BeginInvoke(new UpdateRichEditCallback(OnUpdateRichEdit), pList);

WriteToLogFile(msg);

}

else

{

// This is the main thread which created this control, hence update it directly

OnUpdateRichEdit(msg);

WriteToLogFile(msg);

}

}

/// <summary>

/// This UpdateRichEdit will be run back on the UI thread

/// (using System.EventHandler signature so we don’t need to define a new delegate type here)

/// </summary>

/// <param name=”msg”></param>

private void OnUpdateRichEdit(string msg)

{

richTextBoxReceivedMsg.AppendText(msg + “r”);

}

void CloseSockets()

{

if (m_mainSocket != null)

{

m_mainSocket.Close();

m_mainSocket = null;

}

try

{

Socket workerSocket = null;

for (int i = 0; i < m_workerSocketList.Count; i++)

{

workerSocket = (Socket)m_workerSocketList[i];

if (workerSocket != null)

{

m_workerSocketList.Remove(workerSocket);

workerSocket.Close();

workerSocket = null;

}

}

}

catch

{ }

}

/// <summary>

/// Allows us to send a specific message to a specific client

/// </summary>

/// <param name=”msg”></param>

/// <param name=”clientNumber”></param>

void SendMsgToClient(string msg, int clientNumber)

{

// Convert the reply to byte array

byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg);

if (clientNumber == 1) // send to all available servers

{

for (int i = 0; i < m_workerSocketList.Count; i++)

{

Socket workerSocket = (Socket)m_workerSocketList[i];

if (workerSocket != null)

workerSocket.Send(byData);

}

}

else

{

if (clientNumber != 0)

{

Socket workerSocket = (Socket)m_workerSocketList[clientNumber 1];

if (workerSocket != null)

workerSocket.Send(byData);

}

}

}

/// <summary>

/// Send back a reply to the client using a socket descriptor

/// </summary>

/// <param name=”socketData”>Socket to send the data down</param>

/// <param name=”szData”>Data to send</param>

private static void SendMsgToClient(string szData, SocketPacket socketData)

{

try

{

string replyMsg = “Server Reply,” + szData.ToUpper();

// Convert the reply to byte array

byte[] byData = System.Text.Encoding.ASCII.GetBytes(replyMsg);

Socket workerSocket = (Socket)socketData.m_currentSocket;

workerSocket.Send(byData);

}

catch //(Exception ex)

{

// MessageBox.Show(“Error in SendMsgToClient method: ” + ex.Message + “r” + ex.StackTrace);

}

}

/// <summary>

/// Allows us to send a broadcast message to all our clients

/// </summary>

/// <param name=”msg”>Message to send</param>

private void SendMsgToAllClients(string msg)

{

try

{

msg = “servermsg:” + msg + “n”;

byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg);

Socket workerSocket = null;

for (int i = 0; i < m_workerSocketList.Count; i++)

{

workerSocket = (Socket)m_workerSocketList[i];

if (workerSocket != null)

{

if (workerSocket.Connected)

{

workerSocket.Send(byData);

}

}

}

}

catch //(SocketException se)

{

//MessageBox.Show(se.Message);

}

}

#endregion Socket Methods

}

#region SocketPacket Class

public class SocketPacket

{

// Constructor which takes a Socket and a client number

public SocketPacket(System.Net.Sockets.Socket socket, int clientNumber)

{

m_currentSocket = socket;

m_clientNumber = clientNumber;

}

public System.Net.Sockets.Socket m_currentSocket;

public int m_clientNumber;

// Buffer to store the data sent by the client

public byte[] dataBuffer = new byte[1024];

}

#endregion SocketPacket Class

}

Now simply compile and run. You will now have a server application which is capable of receiving any clients that connect to it on port 10001. Try it with a telnet client i.e. telnet 127.0.0.1 10001

You should see the client connect in the server window and the telnet client should get a response back saying hello with the socket number it’s connected on. Whilst this session is open, try another telnet session and you should see the socket number increase.

In the server app, add some text to the text box and click Send Message. The telnet clients will display the server sent message

That’s all there is to it. In the next part I will knock up a client application that you can use to talk more effectively to the server and have it send commands that it acts upon. For a hint, check out the ProcessCommand method in the server

Good luck!

Si

Steve Jobs takes medical leave of absence | News | TechRadar UK

Steve Jobs takes medical leave of absence

“Complex” health issues means Tim Cook takes over day-to-day running of Apple

9 hours ago | Tell us what you think [ 1 comments ]

steve-jobs-in-happier-days

Steve Jobs in happier days

ZoomZoom

<>

Steve Jobs is stepping down from running Apple, according to a letter released just minutes ago.

Citing medical problems that are “more complex than I originally thought”, Jobs has decided to take a medical leave of absence until June.

We’re all slightly to blame as well, with Jobs noting,”The curiosity over my personal health continues to be a distraction not only for me and my family, but everyone else at Apple as well.”

As we write, after-hours trading shows Apple shares slipping by up to 10 per cent on the news.

Head Cook

On the business side, Chief Operating Officer Tim Cook will step into the breach for day-to-day operations, although Jobs will keep an eye on things.

He says: “As CEO, I plan to remain involved in major strategic decisions while I am out. Our board of directors fully supports this plan.”

Jobs, who has suffered from pancreatic cancer and – more recently – a hormone imbalance, signs off by saying: “I look forward to seeing all of you this summer.”

via Steve Jobs takes medical leave of absence | News | TechRadar UK.

"Donington Will Deliver"

Wow didnt expect this:

Thu 8th Jan 09 – 20:00

Donington Park was today given the green light to proceed with planned circuit developments, which will enable the venue to host the 2010 British Formula One Grand Prix. North West Leicestershire District Council granted planning permission for the first stage of improvements at an evening hearing in Coalville.

The permission was a significant milestone for Chief Executive Simon Gillett, who has spent six years researching and planning the project. Construction, planning and design, which began six months ago, is now complete and a contractor has been appointed. Gillett – who holds a 150-year lease on the circuit – emerged victorious from the hearing, promising that “Donington will deliver”.

Gillett’s comment is likely to have struck a chord with critics who have consistently attacked the plans since Donington Park’s intention was announced last July. The determined entrepreneur has remained committed to delivery and has been insistent that his only response to the sceptics will be successful completion of the development.

“We will definitely be celebrating tonight,” Gillett exclaimed. “This is a major step forward and one more target delivered”. I remain committed to approaching every stage of this development with the same passion and vigour with which we attacked the planning stage and I have endeavoured to ensure that the same is true of the people who will work with me on this project.

“My eye is always on that fixed end date of July 2010. I remain confident and positive that we can and will achieve everything that we have promised and I won’t rest until I am watching the British Grand Prix at Donington Park next year.”

His excitement at the positive news was mirrored by Donington Park landowner Tom Wheatcroft: “I’m delighted to see that the plans have been accepted – there is a lot of work ahead now for everyone and I am looking forward enthusiastically to 2010 and the arrival of the British F1 Grand Prix,”.

“Donington Will Deliver”.