marți, 14 aprilie 2009

Another TCP/IP Server client



Well, it seems I'm supposed to write another Socket based server client application. Since usually all you find on the web are Chat Clones, I decided
to use the time and get a really basic framework going.


First off, we have a basic client



namespace BaseNetworkProtocol
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.ComponentModel;
using System.IO;
/// <summary>
/// The class that contains some methods and properties to manage the remote clients.
/// </summary>
public class Client
{
public ProtocolContext Context;

/// <summary>
/// Gets the IP address of connected remote client.This is 'IPAddress.None' if the client is not connected.
/// </summary>
public IPAddress IP
{
get
{
if ( this.socket != null)
return ( (IPEndPoint)this.socket.RemoteEndPoint ).Address;
else
return IPAddress.None;
}
}
/// <summary>
/// Gets the port number of connected remote client.This is -1 if the client is not connected.
/// </summary>
public int Port
{
get
{
if ( this.socket != null)
return ( (IPEndPoint)this.socket.RemoteEndPoint ).Port;
else
return -1;
}
}
/// <summary>
/// [Gets] The value that specifies the remote client is connected to this server or not.
/// </summary>
public bool Connected
{
get
{
if ( this.socket != null )
return this.socket.Connected;
else
return false;
}
}

private Socket socket;

NetworkStream networkStream;
private BackgroundWorker bwReceiver;

#region Constructor
/// <summary>
/// Creates an instance of ClientManager class to comunicate with remote clients.
/// </summary>
/// <param name="clientSocket">The socket of ClientManager.</param>
public Client(Socket clientSocket, ProtocolContext context)
{
this.Context = context;

this.socket = clientSocket;
this.networkStream = new NetworkStream(this.socket);
this.bwReceiver = new BackgroundWorker();
this.bwReceiver.DoWork += new DoWorkEventHandler(StartReceive);
this.bwReceiver.RunWorkerAsync();
}
#endregion

#region Private Methods
private void StartReceive(object sender , DoWorkEventArgs e)
{
while ( this.socket.Connected )
{
//Read the command's Type.
//byte [] buffer = new byte [sizeof(long)];
//int readBytes = this.networkStream.Read(buffer , 0 , 4);
//if ( readBytes == 0 )
// break;

BasePacket packet = new BasePacket();
try
{
packet = Context.Reader.Read(networkStream);
}
catch (IOException ioex)
{
Disconnect();
}

this.OnPacketReceived(new PacketEventArgs(packet));
}
this.OnDisconnected(new ClientEventArgs(this.socket));
this.Disconnect();
}

private void bwSender_RunWorkerCompleted(object sender , RunWorkerCompletedEventArgs e)
{
if ( !e.Cancelled && e.Error == null && ( (bool)e.Result ) )
this.OnPacketSent(new EventArgs());
else
this.OnPacketFailed(new EventArgs());

( (BackgroundWorker)sender ).Dispose();
GC.Collect();
}

private void bwSender_DoWork(object sender , DoWorkEventArgs e)
{
BasePacket packet = (BasePacket)e.Argument;
e.Result = this.SendPacketToClient(packet);
}

//This Semaphor is to protect the critical section from concurrent access of sender threads.
System.Threading.Semaphore semaphor = new System.Threading.Semaphore(1 , 1);
private bool SendPacketToClient(BasePacket packet)
{

try
{
semaphor.WaitOne();

Context.Writer.Write(networkStream, packet);
networkStream.Flush();
#region Removed Source
////Type
//byte [] buffer = new byte [4];
//buffer = BitConverter.GetBytes((int)cmd.PacketType);
//this.networkStream.Write(buffer , 0 , 4);
//this.networkStream.Flush();


//if (cmd.PacketType != PacketType.Frame)
//{
// //Meta Data.
// if (cmd.MetaData == null || cmd.MetaData == "")
// cmd.MetaData = "\n";

// byte[] metaBuffer = Encoding.Unicode.GetBytes(cmd.MetaData);
// buffer = new byte[4];
// buffer = BitConverter.GetBytes(metaBuffer.Length);
// this.networkStream.Write(buffer, 0, 4);
// this.networkStream.Flush();
// this.networkStream.Write(metaBuffer, 0, metaBuffer.Length);
// this.networkStream.Flush();
//}
//else
//{

// WepFrame encryptedFrame = new WepEncryption(this.Context).For(cmd.Frame);

// new WepFrameWriter(networkStream).Write(encryptedFrame);
//}
#endregion
semaphor.Release();
return true;
}
catch
{
semaphor.Release();
return false;
}
}
#endregion

#region Public Methods
/// <summary>
/// Sends a command to the remote client if the connection is alive.
/// </summary>
/// <param name="cmd">The command to send.</param>
public void SendPacket(BasePacket packet)
{
if ( this.socket != null && this.socket.Connected )
{
BackgroundWorker bwSender = new BackgroundWorker();
bwSender.DoWork += new DoWorkEventHandler(bwSender_DoWork);
bwSender.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bwSender_RunWorkerCompleted);
bwSender.RunWorkerAsync(packet);
}
else
this.OnPacketFailed(new EventArgs());
}



/// <summary>
/// Disconnect the current client manager from the remote client and returns true if the client had been disconnected from the server.
/// </summary>
/// <returns>True if the remote client had been disconnected from the server,otherwise false.</returns>
public bool Disconnect()
{
if (this.socket != null && this.socket.Connected )
{
try
{
this.socket.Shutdown(SocketShutdown.Both);
this.socket.Close();
return true;
}
catch
{
return false;
}
}
else
return true;
}
#endregion

#region Events
/// <summary>
/// Occurs when a command received from a remote client.
/// </summary>
public event PacketReceivedEventHandler PacketReceived;
/// <summary>
/// Occurs when a command received from a remote client.
/// </summary>
/// <param name="e">Received command.</param>
protected virtual void OnPacketReceived(PacketEventArgs e)
{
if ( PacketReceived != null )
PacketReceived(this , e);
}

/// <summary>
/// Occurs when a command had been sent to the remote client successfully.
/// </summary>
public event PacketSentEventHandler PacketSent;
/// <summary>
/// Occurs when a command had been sent to the remote client successfully.
/// </summary>
/// <param name="e">The sent command.</param>
protected virtual void OnPacketSent(EventArgs e)
{
if ( PacketSent != null )
PacketSent(this , e);
}

/// <summary>
/// Occurs when a command sending action had been failed.This is because disconnection or sending exception.
/// </summary>
public event PacketSendingFailedEventHandler PacketFailed;
/// <summary>
/// Occurs when a command sending action had been failed.This is because disconnection or sending exception.
/// </summary>
/// <param name="e">The sent command.</param>
protected virtual void OnPacketFailed(EventArgs e)
{
if ( PacketFailed != null )
PacketFailed(this , e);
}

/// <summary>
/// Occurs when a client disconnected from this server.
/// </summary>
public event DisconnectedEventHandler Disconnected;
/// <summary>
/// Occurs when a client disconnected from this server.
/// </summary>
/// <param name="e">Client information.</param>
protected virtual void OnDisconnected(ClientEventArgs e)
{
if ( Disconnected != null )
Disconnected(this , e);
}

#endregion
}
}



As you can see this is a basic wrapper for the System.Net.Socket class, and it uses a ProtcolContext (listed below ).



namespace BaseNetworkProtocol
{
using System;
using System.Collections.Generic;
using System.Text;
public class ProtocolContext
{
public IProtocolWriter Writer { get; set; }
public IProtocolReader Reader { get; set; }
}
}

which in turn uses a ProtocolReader for reading, and ProtocolWriter for writing to the stream.



public interface IProtocolReader
{
BasePacket Read( Stream stream);

}

and



public interface IProtocolWriter
{
void Write(Stream stream,BasePacket packet);
}

And they read everything into a



public class BasePacket
{
public byte[] Data { get; set; }
}

For convenience I've written down two implementations, that should be sufficient for any type of extension use



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace BaseNetworkProtocol
{
public class BaseProtocolReader:IProtocolReader
{
#region IProtocolReader Members

public virtual BasePacket Read(System.IO.Stream stream)
{

byte[] dataLength = new byte[sizeof(int)];
stream.Read(dataLength, 0, dataLength.Length);
int length = BitConverter.ToInt32(dataLength, 0);


byte[] data = new byte[length];
stream.Read(data, 0, length);
BasePacket packet = new BasePacket();
packet.Data = data;
return packet;


}

#endregion
}
}


And



using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace BaseNetworkProtocol
{
public class BaseProtocolWriter : IProtocolWriter
{
#region IProtocolWriter Members

public virtual void Write(System.IO.Stream stream, BasePacket packet)
{
byte[] dataLength = BitConverter.GetBytes(packet.Data.Length);
stream.Write(dataLength,0,dataLength.Length);
stream.Write(
packet.Data,
0,
packet.Data.Length
);
}

#endregion
}
}


As I said this should be very testable, and here is a simple test for it



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using BaseNetworkProtocol;
using System.IO;

namespace BaseNetworkProtocolTests
{
[TestClass]
public class TestBaseProtcols
{
[TestMethod]
public void should_write_and_read_the_packet_sent()
{
// Arrange
IProtocolWriter writer = new BaseProtocolWriter();
IProtocolReader reader = new BaseProtocolReader();

BasePacket packet = new BasePacket();
packet.Data = new byte[] { 1, 2, 3 };

MemoryStream communicationChannel = new MemoryStream();
// Act

writer.Write(communicationChannel, packet);
communicationChannel.Position = 0;
BasePacket receivedPacket = reader.Read(communicationChannel);
// Assert
Assert.IsNotNull(packet);
Assert.IsNotNull(receivedPacket);
Assert.IsNotNull(packet.Data);
Assert.IsNotNull(receivedPacket.Data);
Assert.AreEqual(packet.Data.Length, receivedPacket.Data.Length);
for (int dataIndex = 0; dataIndex < packet.Data.Length; dataIndex++)
{
Assert.AreEqual(packet.Data[dataIndex],receivedPacket.Data[dataIndex]);
}
// Clean up
communicationChannel.Close();
communicationChannel.Dispose();
}
}

}



All that's left is to provide some type of protocols to it. And, that's through the use of two Services the ClientService, and the ServerService.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using FinancialServer.Properties;
using BaseNetworkProtocol;
using Core.Utils;
using System.Threading;

namespace FinancialServer.Services
{
internal class ServerService : IServer
{
Socket _socket;
Client _currentClient;
ProtocolContext _context;
public ServerService(ProtocolContext context)
{
_context = context;
}
#region IServerService Members

public void Start()
{
_socket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
_socket.Bind(new IPEndPoint(
IPAddress.Parse(Settings.Default.ServerAddress),
Settings.Default.Port));

_socket.Listen(5);
//using(var resolver = Program.Container.CreateInnerContainer()){

new Thread(AcceptClients).Start();
//}

}

public void AcceptClients()
{
while (Program.Resolve<IServer>().IsConnected)
{
try
{
_currentClient = new Client(
_socket.Accept(), Program.Resolve<ProtocolContext>());
}
catch (SocketException soex)
{
// TODO: Log it
break;
}
_currentClient.PacketReceived +=
(sender, @event) =>
{
Client _sender = (Client)sender;
string request = new ResponsePacket(@event.Packet).Message<string>();
var result = Program.Resolve<IRequestProcessor>().Process(request);
if (result != null)
{
_sender.SendPacket(
new RequestPacket(
result
).Packet
);
}
//if (request.Equals("1 + 1"))
//{
// _sender.SendPacket
// (new RequestPacket("2").Packet);
//}

};
}
}

public void Send(string message)
{
BasePacket packet = new BasePacket();
packet.Data = System.Text.Encoding.Unicode.GetBytes(message);
_currentClient.SendPacket(packet);

}

public bool IsConnected
{
get
{
return _socket.IsBound;
}
}
public void Close()
{
if (IsConnected)
_socket.Close();
}
#endregion
}
}



The client



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseNetworkProtocol;
using System.Net.Sockets;
using System.Net;
using FinancialClient.Properties;
using Core;
using Core.Services;

namespace FinancialClient.Services
{
public class ClientService : IClientService
{
ProtocolContext context;
Client client;
public ClientService(IProtocolReader reader,
IProtocolWriter writer)
{
context = new ProtocolContext();
context.Reader = reader;
context.Writer = writer;
}

#region IClientService Members

public bool Connect()
{
Socket socket =
new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
try
{
socket.Connect(
IPAddress.Parse(Settings.Default.ServerAddress),
Settings.Default.Port);
client = new Client(
socket,
context);


}catch(SocketException ex){
//using (var resolver = Program.Container.CreateInnerContainer())
//{
Program.Resolve<IErrorService>().Log(ex);
//}
return false;
}
return true;
}
public void SendPacket(BasePacket packet)
{
client.SendPacket(packet);

}
public void ReceivePacket(PacketReceivedEventHandler executeOnReceive)
{
client.PacketReceived += executeOnReceive;
}
public bool IsConnected
{
get
{
return client.Connected;
}
}

#endregion
}
}


The communication is done through serialized objects like this



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseNetworkProtocol;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;

namespace Core.Utils
{
public class RequestPacket
{
BasePacket basePacket;
public RequestPacket(object request)
{
basePacket = new BasePacket();

IFormatter formatter = new BinaryFormatter();
MemoryStream buffer = new MemoryStream();
formatter.Serialize(buffer, request);
this.basePacket.Data = buffer.ToArray();
}
public BasePacket Packet { get { return basePacket; } }
}
}


And




using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BaseNetworkProtocol;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.IO;

namespace Core.Utils
{
public class ResponsePacket
{
private readonly object message;
public ResponsePacket(BasePacket response)
{
if (response.Data == null) {
message = null;

return; }
IFormatter formatter = new BinaryFormatter();
using(MemoryStream ms =
new MemoryStream(response.Data.ToArray()))
message = formatter.Deserialize(ms);
}
public TOBject Message<TOBject>(){

return (TOBject) message;

}

}
}



Note: This has been an extreeemly loong post. And it's so for me to remind myself all of this classes, so I don't go and search the web for solutions that I don't find simple and extensible enough for my needs. At least it's my code, so if something doesn't work I know who to blame.

luni, 13 aprilie 2009

Creating a 2 steps expression based link

This is a simple post highliting how to build a quick extension to HtmlHelper.
You'll need to use the MVC Futures extensions

For the extension all you need is this

namespace Microsoft.Web.Mvc
{
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using Microsoft.Web.Mvc;
public static class MyLinkExtensions
{
public static void BeginLink<TController>(this HtmlHelper helper,
Expression<Action<TController>> action
) where TController : Controller
{
BeginLink(helper,
action,
new { });
}
public static void BeginLink<TController>(this HtmlHelper helper,
Expression<Action<TController>> action,
object htmlAttributes) where TController : Controller
{
BeginLink(helper,
action,
new RouteValueDictionary(htmlAttributes));
}
public static void BeginLink<TController>(this HtmlHelper helper,
Expression<Action<TController>> action,
IDictionary<string, object> htmlAttributes) where TController : Controller
{
TagBuilder builder = new TagBuilder("a");
builder.MergeAttributes(htmlAttributes);
string href = Microsoft.Web.Mvc.LinkExtensions.BuildUrlFromExpression(helper, action);
builder.MergeAttribute("href", href);

HttpResponseBase httpResponse = helper.ViewContext.HttpContext.Response;
httpResponse.Write(builder.ToString(TagRenderMode.StartTag));

}

public static void EndLink(this HtmlHelper helper)
{
TagBuilder tagBuilder = new TagBuilder("a");
HttpResponseBase httpResponse = helper.ViewContext.HttpContext.Response;
httpResponse.Write(tagBuilder.ToString( TagRenderMode.EndTag));
}
}
}


And to use it, all you need is something like :


<% Html.BeginLink < HomeController >( c=> c.About() ); %>
Link text
<% Html.EndLink(); >


Note: Don't forget to add Microsoft.Web.Mvc to the namespaces that the view uses

sâmbătă, 27 septembrie 2008

Codesqueez

I've started reading about Agile Methodologies. I thought I knew all the stories. Man was I wrong. There is a lot more to Agile than what I thought.



Right now I'm struggling with Velocity and assigning points to user stories. Well I'll find the solution maybe when it's not so late :D.



For the moment I found this really cool post here. If you're interested in increasing your team's speed I urge you to have a look at Agile and learn it.



As usual I'm learning by myself, university keeps disappointing me in this. For our collective project they asked us to use Agile and TDD. LOL - that was a nice. I ended up writing most of it myself. I won't do that never again! ( I hope :-s ).


As usual I continue to babble and I like having a conclusion to what I'm pointing towards ( just in case I haven't already ). So give codesqueez a try for some examples of applied agile.

vineri, 26 septembrie 2008

Why do developers choose Microsoft® ?


Note: This is a post I will probably update once I get more ideas or thoughts I want to share. :)



It should come as no surprise that the majority of today's developer are mostly focused on technologies built on and for the frameworks offered by Microsoft®.

The topic of this post is why is that?

Basically we have an always evolving Market, that is always asking for better tooling and better software. Microsoft® is the biggest supplier of such software having their own operating system, as well as great development tools like Visual Studio and a platform like .Net that makes it easier, faster and funnier to develop programs.

Microsoft also offers Visual Studio® as Express Edition. What this means is that you have people curios about developing on the platforms offered by Microsoft® some nice tools with obvious limitations that let's them test the products and even develop programs.



Whenever you ask someone that is "old" in the industry ( by old I mean he has 10 years+ experience in the field ) they will always choose Microsoft® technologies because life is nicer when it's safer, and with Microsoft® you have the assurance that they will continue to improve the technologies that you are offered.


Most of the times they offer limitations to the products you are offered because there will always be those who will fill the loop holes for personal gain.


It's basically a symbiotic relationship, we pay Microsoft for the software we use. Others pay us to use and extend these products. To be honest I haven't really found any other software organization that gives so many extension points.


There are obviously those who hate that Microsoft® makes so much money and forces you to use their system and that it doesn't integrate nicely with stuff that was not built for their framework. I sometimes wish that I could write once deploy everywhere.

Well There is Mono. And my hopes are that they will do what Microsoft didn't directly do. Novel is the firm that's behind Mono, although it's an open-source project funding comes from the private domain, and Novel has partnerships with Microsoft.

Thinking of conspiracies and such is beyond me. The point is that Microsoft® offers security and a lot of jobs. Since in order to live we require money, it's probably best to have security over hate ;). Just go with the flow and never settle for just one thing.

miercuri, 17 septembrie 2008

Hidden gems of Generic Types

This post could have been called "How to find that a type is of a certain generic type ?"
The solution is so simple I would like not to tell you about it, but just in case it will help someone here it goes :


typeof(int?).GetGenericTypeDefinition() == typeof(Nullable<>)



The example is from something I needed to find out. Whenever you generate a nullable type it gets converted by the compiler into a Nullable. E.g. int? --> Nullable. So the example above should be suffice to point you in the right direction if you're searching for a way to find out if a certain object is of a nullable type ;).

Enjoy and take care.

luni, 1 septembrie 2008

I give up

I've got to 22 words/minute with the keyboard. but since I need to write fast at work since I don't have the resilience to think fast and write slow.. I'm kind'a giving up on the new keyboard at least during the time I need to write fast code.

The really funny part is when I switch from to the other. It's true that I can't expect to switch from something I've used 6+ years to a new layout over night.

Well I'll see what I do

sâmbătă, 30 august 2008

Rough changes

I find that it's necessary to challenge yourself from time to time.

I recently wrote about the qwerty layout, it's designed to make your fingers move allot because that's what solved an engineering problem with the typewriter patented by Sholes.
The QWERTY keyboard layout was devised and created in the early 1870s by Christopher Sholes, a newspaper editor and printer who lived in Milwaukee.

With the assistance of his friends Carlos Glidden and Samuel W. Soule he built an early writing machine for which a patent application was filed in October 1867.[3] However, Sholes' "Type Writer" had many defects: the printing point was located beneath the paper carriage, and so was invisible to the operator. Consequently, the tendency of the typebars to clash and jam if struck in rapid succession was a particularly serious problem, in that the mishap would only be discovered when the typist raised the carriage to inspect what had been typed.[4]

Sholes struggled for the next six years to perfect his invention, making many trial-and-error rearrangements of the original machine's alphabetical key arrangement in an effort to reduce the frequency of typebar clashes. Eventually he arrived at a four-row, upper case keyboard approaching the modern QWERTY standard. In 1873 Sholes' backer, James Densmore, succeeded in selling manufacturing rights for the Sholes-Glidden "Type Writer" with E. Remington and Sons and within the following few months the keyboard layout was finalised by Remington's mechanics. Their adjustments included placing the "R" key in the place previously allotted to the period mark, thus enabling salesmen to impress customers by pecking out the brand name "TYPE WRITER" from one keyboard row. Vestiges of the original alphabetical layout remained in the "home row" sequence FGHJKL.[4]


But where does that leave us? Computers don't have this problem. Why did we get stuck with this faulty layout? The reason is very obvious most people got so used with it that they just started demanding it. And where there's demand there is also offer ( a really symbiotic relationship ).

Getting back on track.. since I found Colemak to be the nicest and newest layout I started learning it. After 5 years of only QWERTY you can imagine how hard learning to walk on the keyboard again has been. Plus that I don't look at the keyboard so I had to keep a mental representation of this new keyboard.

But although the mental stress was hard after 2 days I was able to write this post ;) so all in all it was a nice experience. Are you reader up for it ?