Started working on the debugger. Prepared only the link between master and client app. Have to investigate on the changes in the PATH1 done by Jake.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4106 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
feal87@gmail.com 2010-12-19 15:55:52 +00:00
parent b3c90f21a6
commit 0d0778a5dd
15 changed files with 1787 additions and 72 deletions

View File

@ -8,20 +8,36 @@ using System.Threading;
using System.Diagnostics;
using GSDumpGUI.Properties;
using System.IO;
using TCPLibrary.MessageBased.Core;
namespace GSDumpGUI
{
static class Program
{
static public GSDumpGUI frmMain;
static public TCPLibrary.MessageBased.Core.BaseMessageServer Server;
static public List<TCPLibrary.MessageBased.Core.BaseMessageClientS> Clients;
static public TCPLibrary.MessageBased.Core.BaseMessageClient Client;
static private Boolean ChangeIcon;
static private GSDump dump;
[STAThread]
static void Main(String[] args)
{
if (args.Length == 4)
{
try
{
Client = new TCPLibrary.MessageBased.Core.BaseMessageClient();
Client.OnMessageReceived += new TCPLibrary.MessageBased.Core.BaseMessageClient.MessageReceivedHandler(Client_OnMessageReceived);
Client.Connect("localhost", 9999);
}
catch (Exception)
{
Client = null;
}
Thread thd = new Thread(new ThreadStart(delegate
{
while (true)
@ -55,21 +71,101 @@ namespace GSDumpGUI
Directory.SetCurrentDirectory(Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory + "GSDumpGSDXConfigs\\" + Path.GetFileName(DLLPath) + "\\"));
if (Operation == "GSReplay")
{
GSDump dump = GSDump.LoadDump(DumpPath);
dump = GSDump.LoadDump(DumpPath);
wrap.Run(dump, Renderer);
ChangeIcon = true;
}
else
wrap.GSConfig();
wrap.Unload();
if (Client != null)
Client.Disconnect();
}
else
{
Clients = new List<TCPLibrary.MessageBased.Core.BaseMessageClientS>();
Server = new TCPLibrary.MessageBased.Core.BaseMessageServer();
Server.OnClientMessageReceived += new BaseMessageServer.MessageReceivedHandler(Server_OnClientMessageReceived);
Server.OnClientAfterConnect += new TCPLibrary.Core.Server.ConnectedHandler(Server_OnClientAfterConnect);
Server.OnClientAfterDisconnected += new TCPLibrary.Core.Server.DisconnectedHandler(Server_OnClientAfterDisconnected);
Server.Port = 9999;
Server.Enabled = true;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
frmMain = new GSDumpGUI();
Application.Run(frmMain);
Server.Enabled = false;
}
}
static void Server_OnClientAfterDisconnected(TCPLibrary.Core.Server server, TCPLibrary.Core.ClientS sender)
{
Clients.Remove((TCPLibrary.MessageBased.Core.BaseMessageClientS)sender);
RefreshList();
}
static void Server_OnClientMessageReceived(BaseMessageServer server, BaseMessageClientS sender, TCPMessage Mess)
{
switch (Mess.MessageType)
{
case MessageType.Connect:
break;
case MessageType.MaxUsers:
break;
case MessageType.SizeDump:
frmMain.Invoke(new Action<object>(delegate(object e)
{
frmMain.txtDumpSize.Text = (((int)Mess.Parameters[0]) / 1024f / 1024f).ToString("F2");
}), new object[] { null });
break;
default:
break;
}
}
static void Client_OnMessageReceived(TCPLibrary.Core.Client sender, TCPLibrary.MessageBased.Core.TCPMessage Mess)
{
switch (Mess.MessageType)
{
case TCPLibrary.MessageBased.Core.MessageType.Connect:
break;
case TCPLibrary.MessageBased.Core.MessageType.MaxUsers:
break;
case TCPLibrary.MessageBased.Core.MessageType.SizeDump:
TCPMessage msg = new TCPMessage();
msg.MessageType = MessageType.SizeDump;
if (dump != null)
msg.Parameters.Add(dump.Size);
else
msg.Parameters.Add(0);
Client.Send(msg);
break;
default:
break;
}
}
static void Server_OnClientAfterConnect(TCPLibrary.Core.Server server, TCPLibrary.Core.ClientS sender)
{
Clients.Add((TCPLibrary.MessageBased.Core.BaseMessageClientS)sender);
RefreshList();
}
private static void RefreshList()
{
frmMain.Invoke(new Action<object>( delegate(object e)
{
frmMain.lstProcesses.Items.Clear();
foreach (var itm in Clients)
{
frmMain.lstProcesses.Items.Add(itm.IPAddress);
}
}), new object[] { null});
}
}
}

View File

@ -53,6 +53,12 @@
this.rdaNone = new System.Windows.Forms.RadioButton();
this.lblInternalLog = new System.Windows.Forms.Label();
this.txtIntLog = new System.Windows.Forms.TextBox();
this.lblDebugger = new System.Windows.Forms.Label();
this.lstProcesses = new System.Windows.Forms.ListBox();
this.lblChild = new System.Windows.Forms.Label();
this.lblDumpSize = new System.Windows.Forms.Label();
this.txtDumpSize = new System.Windows.Forms.Label();
this.lblWIP = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.pctBox)).BeginInit();
this.SuspendLayout();
//
@ -303,11 +309,72 @@
this.txtIntLog.TabIndex = 24;
this.txtIntLog.TabStop = false;
//
// lblDebugger
//
this.lblDebugger.AutoSize = true;
this.lblDebugger.Location = new System.Drawing.Point(417, 470);
this.lblDebugger.Name = "lblDebugger";
this.lblDebugger.Size = new System.Drawing.Size(54, 13);
this.lblDebugger.TabIndex = 26;
this.lblDebugger.Text = "Debugger";
//
// lstProcesses
//
this.lstProcesses.FormattingEnabled = true;
this.lstProcesses.Location = new System.Drawing.Point(12, 502);
this.lstProcesses.Name = "lstProcesses";
this.lstProcesses.Size = new System.Drawing.Size(248, 251);
this.lstProcesses.TabIndex = 27;
this.lstProcesses.SelectedIndexChanged += new System.EventHandler(this.lstProcesses_SelectedIndexChanged);
//
// lblChild
//
this.lblChild.AutoSize = true;
this.lblChild.Location = new System.Drawing.Point(9, 487);
this.lblChild.Name = "lblChild";
this.lblChild.Size = new System.Drawing.Size(82, 13);
this.lblChild.TabIndex = 28;
this.lblChild.Text = "Child Processes";
//
// lblDumpSize
//
this.lblDumpSize.AutoSize = true;
this.lblDumpSize.Location = new System.Drawing.Point(279, 487);
this.lblDumpSize.Name = "lblDumpSize";
this.lblDumpSize.Size = new System.Drawing.Size(58, 13);
this.lblDumpSize.TabIndex = 29;
this.lblDumpSize.Text = "Dump Size";
//
// txtDumpSize
//
this.txtDumpSize.AutoSize = true;
this.txtDumpSize.Location = new System.Drawing.Point(279, 502);
this.txtDumpSize.Name = "txtDumpSize";
this.txtDumpSize.Size = new System.Drawing.Size(0, 13);
this.txtDumpSize.TabIndex = 30;
//
// lblWIP
//
this.lblWIP.AutoSize = true;
this.lblWIP.Font = new System.Drawing.Font("Times New Roman", 48F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.lblWIP.ForeColor = System.Drawing.Color.Red;
this.lblWIP.Location = new System.Drawing.Point(407, 589);
this.lblWIP.Name = "lblWIP";
this.lblWIP.Size = new System.Drawing.Size(508, 73);
this.lblWIP.TabIndex = 31;
this.lblWIP.Text = "Work in Progress";
//
// GSDumpGUI
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(988, 467);
this.ClientSize = new System.Drawing.Size(988, 766);
this.Controls.Add(this.lblWIP);
this.Controls.Add(this.txtDumpSize);
this.Controls.Add(this.lblDumpSize);
this.Controls.Add(this.lstProcesses);
this.Controls.Add(this.lblChild);
this.Controls.Add(this.lblDebugger);
this.Controls.Add(this.lblInternalLog);
this.Controls.Add(this.txtIntLog);
this.Controls.Add(this.rdaNone);
@ -372,6 +439,12 @@
private System.Windows.Forms.RadioButton rdaNone;
private System.Windows.Forms.Label lblInternalLog;
private System.Windows.Forms.TextBox txtIntLog;
private System.Windows.Forms.Label lblDebugger;
private System.Windows.Forms.Label lblChild;
public System.Windows.Forms.ListBox lstProcesses;
private System.Windows.Forms.Label lblDumpSize;
public System.Windows.Forms.Label txtDumpSize;
private System.Windows.Forms.Label lblWIP;
}
}

View File

@ -10,6 +10,7 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
using System.Security;
using TCPLibrary.MessageBased.Core;
namespace GSDumpGUI
{
@ -351,5 +352,15 @@ namespace GSDumpGUI
Properties.Settings.Default.DumpDir = txtDumpsDirectory.Text;
Properties.Settings.Default.Save();
}
private void lstProcesses_SelectedIndexChanged(object sender, EventArgs e)
{
if (lstProcesses.SelectedIndex != -1)
{
TCPMessage msg = new TCPMessage();
msg.MessageType = MessageType.SizeDump;
Program.Clients.Find(a => a.IPAddress == lstProcesses.SelectedItem.ToString()).Send(msg);
}
}
}
}

View File

@ -59,6 +59,15 @@
<Compile Include="Library\GSDXWrapper.cs" />
<Compile Include="Library\NativeMethods.cs" />
<Compile Include="Core\Program.cs" />
<Compile Include="Library\TCPLibrary\Message\BaseMessageClient.cs" />
<Compile Include="Library\TCPLibrary\Message\BaseMessageClientS.cs" />
<Compile Include="Library\TCPLibrary\Message\BaseMessageServer.cs" />
<Compile Include="Library\TCPLibrary\Base\CancelArgs.cs" />
<Compile Include="Library\TCPLibrary\Base\Client.cs" />
<Compile Include="Library\TCPLibrary\Base\ClientS.cs" />
<Compile Include="Library\TCPLibrary\Base\Data.cs" />
<Compile Include="Library\TCPLibrary\Base\Server.cs" />
<Compile Include="Library\TCPLibrary\Message\TCPMessage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Forms\frmMain.resx">
<DependentUpon>frmMain.cs</DependentUpon>

View File

@ -186,52 +186,7 @@ namespace GSDumpGUI
}
foreach (var itm in dump.Data)
{
switch (itm.id)
{
case GSType.Transfer:
switch (itm.data[0])
{
case 0:
fixed (byte* gifdata = itm.data)
{
byte[] data = new byte[4];
data[0]=*(gifdata+1);
data[1]=*(gifdata+2);
data[2]=*(gifdata+3);
data[3]=*(gifdata+4);
Int32 size = BitConverter.ToInt32(data, 0);
GSgifTransfer1(new IntPtr(gifdata + 5), 16384 - size);
}
break;
case 1:
fixed (byte* gifdata = itm.data)
{
GSgifTransfer2(new IntPtr(gifdata + 1), (itm.data.Length - 1) / 16);
}
break;
case 2:
fixed (byte* gifdata = itm.data)
{
GSgifTransfer3(new IntPtr(gifdata + 1), (itm.data.Length - 1) / 16);
}
break;
}
break;
case GSType.VSync:
GSVSync(itm.data[0]);
break;
case GSType.ReadFIFO2:
fixed (byte* FIFO = itm.data)
{
GSreadFIFO2(new IntPtr(FIFO), itm.data.Length / 16);
}
break;
case GSType.Registers:
Marshal.Copy(itm.data, 0, new IntPtr(pointer), 8192);
break;
default:
break;
}
Step(itm, pointer);
}
}
@ -241,6 +196,57 @@ namespace GSDumpGUI
}
}
private unsafe void Step(GSData itm, byte* registers)
{
switch (itm.id)
{
case GSType.Transfer:
switch (itm.data[0])
{/*
case 0:
byte[] data = new byte[16384];
for (int i = 0; i < itm.data; i++)
{
}
fixed (byte* gifdata = data)
{
GSgifTransfer1(new IntPtr(gifdata + 5), 16384 - size);
}
break;*/
case 0:
case 1:
case 2:
fixed (byte* gifdata = itm.data)
{
GSgifTransfer2(new IntPtr(gifdata + 1), (itm.data.Length - 1) / 16);
}
break;/*
case 2:
fixed (byte* gifdata = itm.data)
{
GSgifTransfer3(new IntPtr(gifdata + 1), (itm.data.Length - 1) / 16);
}
break;*/
}
break;
case GSType.VSync:
GSVSync(itm.data[0]);
break;
case GSType.ReadFIFO2:
fixed (byte* FIFO = itm.data)
{
GSreadFIFO2(new IntPtr(FIFO), itm.data.Length / 16);
}
break;
case GSType.Registers:
Marshal.Copy(itm.data, 0, new IntPtr(registers), 8192);
break;
default:
break;
}
}
public void Stop()
{
Running = false;

View File

@ -11,6 +11,22 @@ namespace GSDumpGUI
public byte[] StateData;
public byte[] Registers; // 8192 bytes
public int Size
{
get
{
int size = 0;
size = 4;
size += StateData.Length;
size += Registers.Length;
foreach (var itm in Data)
{
size += itm.data.Length;
}
return size;
}
}
public List<GSData> Data;
public GSDump()
@ -37,31 +53,12 @@ namespace GSDumpGUI
{
case GSType.Transfer:
byte index = br.ReadByte();
if (index == 0)
{
Int32 size = br.ReadInt32();
Int32 size = br.ReadInt32();
byte[] dat = new byte[16384];
List<byte> Data = new List<byte>();
Data.Add(index);
Data.AddRange(BitConverter.GetBytes(size));
Data.AddRange(dat);
int startaddr = 16389 - size;
for (int i = 0; i < size; i++)
Data[startaddr + i] = br.ReadByte();
data.data = Data.ToArray();
}
else
{
Int32 size = br.ReadInt32();
List<byte> Data = new List<byte>();
Data.Add(index);
Data.AddRange(br.ReadBytes(size));
data.data = Data.ToArray();
}
List<byte> Data = new List<byte>();
Data.Add(index);
Data.AddRange(br.ReadBytes(size));
data.data = Data.ToArray();
break;
case GSType.VSync:
data.data = br.ReadBytes(1);

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2009 Ferreri Alessio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace TCPLibrary.Core
{
/// <summary>
/// Class for containing information regarding the acceptance of a determinate situation.
/// </summary>
public class CancelArgs
{
/// <summary>
/// Whether the operation should be cancelled.
/// </summary>
private Boolean _cancel;
/// <summary>
/// Get/set the flag that determines if the operation should be cancelled.
/// </summary>
public Boolean Cancel
{
get { return _cancel; }
set { _cancel = value; }
}
/// <summary>
/// Base constructor of the class.
/// </summary>
/// <param name="cancel">Whether the operation should be cancelled.</param>
public CancelArgs(Boolean cancel)
{
this._cancel = cancel;
}
}
}

View File

@ -0,0 +1,323 @@
/*
* Copyright (c) 2009 Ferreri Alessio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
using System.ComponentModel;
using System.Text;
using System.Diagnostics;
namespace TCPLibrary.Core
{
/// <summary>
/// Base TCP client class wrapped around TcpClient.
/// </summary>
public class Client
{
/// <summary>
/// Lock object to assure that certain operation over the socket class are executed
/// in an exclusive way.
/// </summary>
private Object _lock;
/// <summary>
/// Wrapper around the Network Stream of the socket. (Read-Only)
/// </summary>
private BinaryReader tr;
/// <summary>
/// Wrapper around the Network Stream of the socket. (Write-Only)
/// </summary>
private BinaryWriter tw;
/// <summary>
/// Address to which the client is connected.
/// </summary>
private IPEndPoint _address;
/// <summary>
/// Flag to permit thread exit from the external.
/// </summary>
protected Boolean _active;
/// <summary>
/// Socket maintaining the connection.
/// </summary>
protected TcpClient _socket;
/// <summary>
/// Get/set the address to which the client is connected.
/// </summary>
public IPEndPoint Address
{
get { return _address; }
}
/// <summary>
/// Get the state of the connection.
/// </summary>
public Boolean Connected
{
get { return _socket != null; }
}
/// <summary>
/// Delegate for the event of receiving/sending a line of data from/to the server.
/// </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="Data">Line of data received.</param>
public delegate void DataCommunicationHandler(Client sender, Data Data);
/// <summary>
/// Occurs when a line of data is received from the server.
/// </summary>
public event DataCommunicationHandler OnDataReceived;
/// <summary>
/// Occurs before the client send a line of data to the server.
/// </summary>
public event DataCommunicationHandler OnBeforeDataSent;
/// <summary>
/// Occurs after the client send a line of data to the server.
/// </summary>
public event DataCommunicationHandler OnAfterDataSent;
/// <summary>
/// Delegate for the event of connection/disconnection to the server.
/// </summary>
/// <param name="sender">Sender of the event.</param>
public delegate void ConnectionStateHandler(Client sender);
/// <summary>
/// Occurs when the client successfully connect the server.
/// </summary>
public event ConnectionStateHandler OnConnected;
/// <summary>
/// Occurs when the client is disconnected from the server.
/// </summary>
public event ConnectionStateHandler OnDisconnected;
/// <summary>
/// Delegate for the event of connection failed for rejection by the server.
/// </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="Message">Message of fail sent by the server.</param>
public delegate void ConnectionFailedHandler(Client sender, byte[] Message);
/// <summary>
/// Occurs when the client failed to connect to the server because the server rejected the connection.
/// </summary>
public event ConnectionFailedHandler OnConnectFailed;
/// <summary>
/// Base constructor of the class.
/// </summary>
public Client()
{
_lock = new object();
_address = null;
}
/// <summary>
/// Try to connect to the server specified.
/// </summary>
/// <param name="Indirizzo">Address of the server to connect.</param>
/// <param name="Port">Port of the server to connect.</param>
/// <returns>True if the connection is successfull, false otherwise.</returns>
/// <exception cref="TCPLibrary.Core.AlreadyConnectedException" />
/// <exception cref="System.Net.Sockets.SocketException" />
public virtual Boolean Connect(String Indirizzo, Int32 Port)
{
if (!Connected)
{
IPHostEntry addr = Dns.GetHostEntry(Indirizzo);
IPAddress ip = null;
foreach (var itm in addr.AddressList)
{
if (itm.AddressFamily == AddressFamily.InterNetwork)
{
ip = itm;
break;
}
}
if (ip != null)
{
_address = new IPEndPoint(ip, Port);
_socket = new TcpClient();
try
{
_socket.Connect(_address);
}
catch (SocketException)
{
_socket = null;
_address = null;
throw;
}
tr = new BinaryReader(_socket.GetStream());
tw = new BinaryWriter(_socket.GetStream());
// Receive the confirmation of the status of the connection to the server.
// Is CONNECTEDTCPSERVER if the connection is successfull, all other cases are wrong.
Int32 Length = Convert.ToInt32(tr.ReadInt32());
byte[] arr = new byte[Length];
tr.Read(arr, 0, Length);
ASCIIEncoding ae = new ASCIIEncoding();
String Accept = ae.GetString(arr, 0, arr.Length);
if (Accept == "CONNECTEDTCPSERVER")
{
_active = true;
Thread thd = new Thread(new ThreadStart(MainThread));
thd.IsBackground = true;
thd.Name = "Client connected to " + Indirizzo + ":" + Port.ToString();
thd.Start();
if (OnConnected != null)
OnConnected(this);
return true;
}
else
{
Stop();
if (OnConnectFailed != null)
OnConnectFailed(this, arr);
return false;
}
}
else
return false;
}
else
throw new ArgumentException("The client is already connected!");
}
/// <summary>
/// Disconnect a Client if connected.
/// </summary>
public virtual void Disconnect()
{
lock (_lock)
{
_active = false;
tr.Close();
tw.Close();
}
}
/// <summary>
/// Disconnect a Client if connected.
/// </summary>
protected virtual void Stop()
{
if (_socket != null)
{
tr.Close();
tw.Close();
_socket.Close();
_socket = null;
_address = null;
if (OnDisconnected != null)
OnDisconnected(this);
}
}
/// <summary>
/// Thread function that actually run the socket work.
/// </summary>
private void MainThread()
{
while (_active)
{
byte[] arr = null;
try
{
int length = Convert.ToInt32(tr.ReadInt32());
arr = new byte[length];
int index = 0;
while (length > 0)
{
int receivedBytes = tr.Read(arr, index, length);
length -= receivedBytes;
index += receivedBytes;
}
}
catch (Exception) { }
lock (_lock)
{
if (_active)
{
Boolean Stato = _socket.Client.Poll(100, SelectMode.SelectRead);
if ((arr == null) && (Stato == true))
break;
else
if (OnDataReceived != null)
OnDataReceived(this, new Data(arr));
}
else
break;
}
}
Stop();
}
/// <summary>
/// Send a line of data to the server.
/// </summary>
/// <param name="msg">Data to send to the server.</param>
/// <exception cref="TCPLibrary.Core.NotConnectedException" />
public void Send(Data msg)
{
if (_active)
{
if (OnBeforeDataSent != null)
OnBeforeDataSent(this, msg);
try
{
tw.Write(msg.Message.Length);
tw.Write(msg.Message);
tw.Flush();
if (OnAfterDataSent != null)
OnAfterDataSent(this, msg);
}
catch (IOException)
{
// Pensare a cosa fare quà. Questo è il caso in cui il server ha chiuso forzatamente
// la connessione mentre il client mandava roba.
}
}
else
throw new ArgumentException("The link is closed. Unable to send data.");
}
}
}

View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 2009 Ferreri Alessio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Diagnostics;
namespace TCPLibrary.Core
{
/// <summary>
/// Base class that manages the single connection between a client and the server.
/// </summary>
public class ClientS
{
/// <summary>
/// Lock object to assure that certain operation over the socket class are executed
/// in an exclusive way.
/// </summary>
private Object _lock;
/// <summary>
/// Wrapper around the Network Stream of the socket. (Read-Only)
/// </summary>
private BinaryReader tr;
/// <summary>
/// Wrapper around the Network Stream of the socket. (Write-Only)
/// </summary>
private BinaryWriter tw;
/// <summary>
/// Current IP address of the client.
/// </summary>
private String _ipaddress;
/// <summary>
/// Flag to permit thread exit from the external.
/// </summary>
protected Boolean _active;
/// <summary>
/// Link to the server to which this client is connected.
/// </summary>
protected Server _server;
/// <summary>
/// Actual socket of the client.
/// </summary>
protected TcpClient _client;
/// <summary>
/// Get the state of the connection.
/// </summary>
public Boolean Connected
{
get { return _client != null; }
}
/// <summary>
/// IP Address of the client.
/// </summary>
public String IPAddress
{
get { return _ipaddress; }
}
/// <summary>
/// Base class constructor.
/// </summary>
/// <param name="server">Server to which this client is linked to.</param>
/// <param name="client">Socket of the client.</param>
protected internal ClientS(Server server, TcpClient client)
{
_lock = new object();
_active = true;
_server = server;
_client = client;
_ipaddress = _client.Client.RemoteEndPoint.ToString();
NetworkStream ns = _client.GetStream();
tr = new BinaryReader(ns);
tw = new BinaryWriter(ns);
}
/// <summary>
/// Start up the thread managing this Client-Server connection.
/// </summary>
protected internal virtual void Start()
{
Thread _thread = new Thread(new ThreadStart(MainThread));
_thread.IsBackground = true;
_thread.Name = "Thread Client " + _ipaddress;
_thread.Start();
}
/// <summary>
/// Thread function that actually run the socket work.
/// </summary>
private void MainThread()
{
while (_active)
{
byte[] arr = null;
try
{
int length = Convert.ToInt32(tr.ReadInt32());
arr = new byte[length];
int index = 0;
while (length > 0)
{
int receivedBytes = tr.Read(arr, index, length);
length -= receivedBytes;
index += receivedBytes;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
lock (_lock)
{
if (_active)
{
Boolean Stato = _client.Client.Poll(100, SelectMode.SelectRead);
if ((arr == null) && (Stato == true))
break;
else
_server.RaiseDataReceivedEvent(this, new Data(arr));
}
else
break;
}
}
Stop();
}
/// <summary>
/// Send a line of data to the client.
/// </summary>
/// <param name="Data">Data to send to the client.</param>
/// <exception cref="TCPLibrary.Core.NotConnectedException" />
public void Send(Data Data)
{
if (_active)
{
_server.RaiseBeforeDataSentEvent(this, Data);
try
{
tw.Write(Data.Message.Length);
tw.Write(Data.Message);
tw.Flush();
_server.RaiseAfterDataSentEvent(this, Data);
}
catch (Exception ex)
{
Debug.Write(ex.ToString());
// Pensare a cosa fare quà. Questo è il caso in cui il client ha chiuso forzatamente
// la connessione mentre il server mandava roba.
}
}
else
throw new ArgumentException("The link is closed. Unable to send data.");
}
/// <summary>
/// Close the link between Client e Server.
/// </summary>
public void Disconnect()
{
lock (_lock)
{
_active = false;
tr.Close();
tw.Close();
}
}
/// <summary>
/// Close the link between Client e Server.
/// </summary>
protected internal void Stop()
{
if (_client != null)
{
_server.RaiseClientBeforeDisconnectedEvent(this);
tr.Close();
tw.Close();
_client.Close();
_client = null;
lock (_server.Clients)
{
_server.Clients.Remove(this);
}
_server.RaiseClientAfterDisconnectedEvent(this);
}
}
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2009 Ferreri Alessio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
namespace TCPLibrary.Core
{
/// <summary>
/// Structure for containing the data to be sent over a base client/server
/// </summary>
public class Data
{
/// <summary>
/// Data to be sent.
/// </summary>
private byte[] _message;
/// <summary>
/// Get/set the data to be sent.
/// </summary>
public byte[] Message
{
get { return _message; }
set { _message = value; }
}
/// <summary>
/// Base constructor of the class.
/// </summary>
/// <param name="msg">Data to be sent.</param>
public Data(byte[] msg)
{
this._message = msg;
}
}
}

View File

@ -0,0 +1,365 @@
/*
* Copyright (c) 2009 Ferreri Alessio
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.ComponentModel;
using System.Text;
namespace TCPLibrary.Core
{
/// <summary>
/// Base TCP server class wrapped around TcpListener.
/// </summary>
public class Server
{
/// <summary>
/// Socket maintaining the connection.
/// </summary>
private TcpListener _socket;
/// <summary>
/// Port to which the server will listen.
/// </summary>
private Int32 _port;
/// <summary>
/// Whether the server is enabled or not.
/// </summary>
private Boolean _enabled;
/// <summary>
/// List of the clients connected to the server.
/// </summary>
private List<ClientS> _clients;
/// <summary>
/// Number of connection permitted in the backlog of the server.
/// </summary>
private Int32 _connectionbacklog;
/// <summary>
/// Delegate for the event of the Enabled property change.
/// </summary>
/// <param name="sender">Sender of the event.</param>
public delegate void EnabledChangedHandler(Server sender);
/// <summary>
/// Occurs when the Enabled property is changed.
/// </summary>
public event EnabledChangedHandler OnEnabledChanged;
/// <summary>
/// Delegate for the event of receiving a line of data from a client.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="client">Client involved in the communication.</param>
/// <param name="Data">Line of data received.</param>
public delegate void DataCommunicationHandler(Server server, ClientS client, Data Data);
/// <summary>
/// Occurs when a client send a line of data to the server.
/// </summary>
public event DataCommunicationHandler OnClientDataReceived;
/// <summary>
/// Occurs before the server send a line of data to a client.
/// </summary>
public event DataCommunicationHandler OnClientBeforeDataSent;
/// <summary>
/// Occurs after the server send a line of data to a client.
/// </summary>
public event DataCommunicationHandler OnClientAfterDataSent;
/// <summary>
/// Delegate for the event of a connection of a client.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="sender">The new client connected.</param>
public delegate void ConnectedHandler(Server server, ClientS sender);
/// <summary>
/// Occurs after a client is connected to the server.
/// </summary>
public event ConnectedHandler OnClientAfterConnect;
/// <summary>
/// Delegate for the event of a connection of a client.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="client">The new client to be connected.</param>
/// <param name="args">Specify if the client should be accepted into the server.</param>
public delegate void BeforeConnectedHandler(Server server, ClientS client, CancelArgs args);
/// <summary>
/// Occurs before a client is allowed to connect to the server.
/// </summary>
public event BeforeConnectedHandler OnClientBeforeConnect;
/// <summary>
/// Delegate for the event of disconnection of a client.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="sender">The client disconnected.</param>
public delegate void DisconnectedHandler(Server server, ClientS sender);
/// <summary>
/// Occurs right after a client disconnect from the server.
/// </summary>
public event DisconnectedHandler OnClientAfterDisconnected;
/// <summary>
/// Occurs before a client disconnect from the server.
/// </summary>
public event DisconnectedHandler OnClientBeforeDisconnected;
/// <summary>
/// Get/set the port number to which the server will listen. Cannot be set while the server is active.
/// </summary>
/// <exception cref="TCPLibrary.Core.ServerAttivoException" />
public Int32 Port
{
get { return _port; }
set
{
if (Enabled == false)
_port = value;
else
throw new ArgumentException("Impossibile eseguire l'operazione a server attivo");
}
}
/// <summary>
/// Get/set the enabled state of the server. Setting this to true will actually activate the server.
/// </summary>
/// <exception cref="System.Net.Sockets.SocketException" />
public Boolean Enabled
{
get { return _enabled; }
set
{
if (value == true)
{
if (_enabled == false)
ActivateServer();
}
else
{
if (_enabled == true)
DeactivateServer();
}
}
}
/// <summary>
/// Get/set the number of connection permitted in the backlog of the server.
/// </summary>
/// <exception cref="TCPLibrary.Core.ServerAttivoException" />
public Int32 ConnectionBackLog
{
get { return _connectionbacklog; }
set
{
if (Enabled == false)
_connectionbacklog = value;
else
throw new ArgumentException("Impossibile eseguire l'operazione a server attivo");
}
}
/// <summary>
/// Get the list of the clients connected to the server.
/// </summary>
public List<ClientS> Clients
{
get { return _clients; }
}
/// <summary>
/// Deactivate the server.
/// </summary>
protected virtual void DeactivateServer()
{
_enabled = false;
_socket.Stop();
_socket = null;
lock (_clients)
{
for (int i = 0; i < _clients.Count; i++)
_clients[i].Disconnect();
}
if (OnEnabledChanged != null)
OnEnabledChanged(this);
}
/// <summary>
/// Activate the server.
/// </summary>
protected virtual void ActivateServer()
{
_socket = new TcpListener(IPAddress.Any, Port);
_socket.Start(ConnectionBackLog);
Thread thd = new Thread(new ThreadStart(MainThread));
thd.Name = "Server on port " + Port.ToString();
thd.IsBackground = true;
thd.Start();
_enabled = true;
if (OnEnabledChanged != null)
OnEnabledChanged(this);
}
/// <summary>
/// Broadcast a line of data to all the clients connected to the server.
/// </summary>
/// <param name="Data">Line of data to be sent.</param>
/// <exception cref="TCPLibrary.Core.ServerNonAttivoException" />
public void Broadcast(Data Data)
{
if (Enabled)
{
lock (_clients)
{
foreach (var itm in _clients)
if (itm.Connected)
itm.Send(Data);
}
}
else
throw new ArgumentException("Unable to execute this operation when the server is inactive.");
}
/// <summary>
/// Base constructor of the class.
/// </summary>
public Server()
{
_clients = new List<ClientS>();
_port = 0;
_connectionbacklog = 0;
_enabled = false;
}
/// <summary>
/// Thread function that actually run the server socket work.
/// </summary>
private void MainThread()
{
try
{
while (Enabled == true)
{
TcpClient client = _socket.AcceptTcpClient();
CancelArgs args = new CancelArgs(false);
ClientS cl = CreateClient(client);
if (OnClientBeforeConnect != null)
OnClientBeforeConnect(this, cl, args);
if (args.Cancel != true)
{
lock (_clients)
{
_clients.Add(cl);
}
ASCIIEncoding ae = new ASCIIEncoding();
byte[] arr = ae.GetBytes("CONNECTEDTCPSERVER");
cl.Send(new Data(arr));
if (OnClientAfterConnect != null)
OnClientAfterConnect(this, cl);
cl.Start();
}
else
{
client.GetStream().Close();
client.Close();
}
}
}
catch (SocketException)
{
Enabled = false;
}
}
/// <summary>
/// Overridable function that create the structure to memorize the client data.
/// </summary>
/// <param name="socket">Socket of the client.</param>
/// <returns>The structure in which memorize all the information of the client.</returns>
protected virtual ClientS CreateClient(TcpClient socket)
{
ClientS cl = new ClientS(this, socket);
return cl;
}
/// <summary>
/// Raise the OnClientAfterDataSent event.
/// </summary>
/// <param name="cl">Client that raised the event.</param>
/// <param name="data">Line of data sent.</param>
internal void RaiseAfterDataSentEvent(ClientS cl, Data data)
{
if (OnClientAfterDataSent != null)
OnClientAfterDataSent(this, cl, data);
}
/// <summary>
/// Raise the OnClientBeforeDataSent event.
/// </summary>
/// <param name="cl">Client that raised the event.</param>
/// <param name="data">Line of data sent.</param>
internal void RaiseBeforeDataSentEvent(ClientS cl, Data data)
{
if (OnClientBeforeDataSent != null)
OnClientBeforeDataSent(this, cl, data);
}
/// <summary>
/// Raise the OnDataReceived event.
/// </summary>
/// <param name="cl">Client that raised the event.</param>
/// <param name="data">Line of data received.</param>
internal void RaiseDataReceivedEvent(ClientS cl, Data data)
{
if (OnClientDataReceived != null)
OnClientDataReceived(this, cl, data);
}
/// <summary>
/// Raise the OnClientAfterDisconnected event.
/// </summary>
/// <param name="cl">Client that raised the event.</param>
internal void RaiseClientAfterDisconnectedEvent(ClientS cl)
{
if (OnClientAfterDisconnected != null)
OnClientAfterDisconnected(this, cl);
}
/// <summary>
/// Raise the OnClientBeforeDisconnected event.
/// </summary>
/// <param name="cl">Client that raised the event.</param>
internal void RaiseClientBeforeDisconnectedEvent(ClientS cl)
{
if (OnClientBeforeDisconnected != null)
OnClientBeforeDisconnected(this, cl);
}
}
}

View File

@ -0,0 +1,137 @@
/*
The MIT License
Copyright (c) 2008 Ferreri Alessio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using TCPLibrary.MessageBased.Core;
using TCPLibrary.Core;
using System;
namespace TCPLibrary.MessageBased.Core
{
/// <summary>
/// TCP Client Class that work with Message structures.
/// </summary>
public class BaseMessageClient : Client
{
/// <summary>
/// Delegate for the event of receiving a message structure from the server.
/// </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="Mess">Message received.</param>
public delegate void MessageReceivedHandler(Client sender, TCPMessage Mess);
/// <summary>
/// Occurs when the client receive a message structure from the server.
/// </summary>
public event MessageReceivedHandler OnMessageReceived;
/// <summary>
/// Delegate for the event of sending a message structure to the server.
/// </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="Mess">Message sent.</param>
public delegate void MessageSentHandler(Client sender, TCPMessage Mess);
/// <summary>
/// Occurs before the client send a message structure to the server.
/// </summary>
public event MessageSentHandler OnBeforeMessageSent;
/// <summary>
/// Occurs after the client send a message structure to the server.
/// </summary>
public event MessageSentHandler OnAfterMessageSent;
/// <summary>
/// Delegate for the event of connection fail for max users number reached.
/// </summary>
/// <param name="sender">Sender of the event.</param>
public delegate void MaxUsersReached(Client sender);
/// <summary>
/// Occurs when the connection fail as the server reached the maximum number of clients allowed.
/// </summary>
public event MaxUsersReached OnMaxUsersConnectionFail;
/// <summary>
/// Base constructor of the class.
/// </summary>
public BaseMessageClient()
{
OnDataReceived += new DataCommunicationHandler(BaseMessageClient_OnDataReceived);
OnAfterDataSent += new DataCommunicationHandler(BaseMessageClient_OnDataSent);
OnConnectFailed += new ConnectionFailedHandler(BaseMessageClient_OnConnectFailed);
}
/// <summary>
/// When the connection is rejected by the server raise the correct event.
/// </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="Message">Message of the server.</param>
void BaseMessageClient_OnConnectFailed(Client sender, byte[] Message)
{
if (TCPLibrary.MessageBased.Core.TCPMessage.FromByteArray(Message).MessageType == MessageType.MaxUsers)
if (OnMaxUsersConnectionFail != null)
OnMaxUsersConnectionFail(sender);
}
/// <summary>
/// Parse the raw data sent to the server and create Message structures.
/// </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="Data">Line of data sent.</param>
void BaseMessageClient_OnDataSent(Client sender, Data Data)
{
TCPMessage msg = TCPMessage.FromByteArray(Data.Message);
if (OnAfterMessageSent != null)
OnAfterMessageSent(sender, msg);
}
/// <summary>
/// Parse the raw data received from the server and create Message structures.
/// </summary>
/// <param name="sender">Sender of the event.</param>
/// <param name="Data">Line of data received.</param>
void BaseMessageClient_OnDataReceived(Client sender, Data Data)
{
TCPMessage msg = null;
try
{
msg = TCPMessage.FromByteArray(Data.Message);
}
catch (Exception)
{
}
if (msg != null)
if (OnMessageReceived != null)
OnMessageReceived(sender, msg);
}
/// <summary>
/// Send a message structure to the server.
/// </summary>
/// <param name="msg">Message structure to be send.</param>
/// <exception cref="TCPLibrary.Core.NotConnectedException"></exception>
public void Send(TCPMessage msg)
{
if (OnBeforeMessageSent != null)
OnBeforeMessageSent(this, msg);
base.Send(new Data(msg.ToByteArray()));
}
}
}

View File

@ -0,0 +1,59 @@
/*
The MIT License
Copyright (c) 2008 Ferreri Alessio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System.Net.Sockets;
using TCPLibrary.Core;
using TCPLibrary.MessageBased.Core;
namespace TCPLibrary.MessageBased.Core
{
/// <summary>
/// Class that manages the single connection between a client and the server based
/// on Message structures.
/// </summary>
public class BaseMessageClientS : ClientS
{
/// <summary>
/// Base constructor of the class.
/// </summary>
/// <param name="server">Server to which this client is linked to.</param>
/// <param name="client">Socket of the client.</param>
protected internal BaseMessageClientS(Server server, TcpClient client)
: base(server, client)
{
}
/// <summary>
/// Send a Message structure to the client.
/// </summary>
/// <param name="msg">Message to be sent.</param>
/// <exception cref="TCPLibrary.Core.NotConnectedException" />
public void Send(TCPMessage msg)
{
((BaseMessageServer)_server).RaiseBeforeMessageSentEvent(this, msg);
base.Send(new Data(msg.ToByteArray()));
}
}
}

View File

@ -0,0 +1,186 @@
/*
The MIT License
Copyright (c) 2008 Ferreri Alessio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using TCPLibrary.MessageBased.Core;
using System.Net.Sockets;
using System.Threading;
using TCPLibrary.Core;
namespace TCPLibrary.MessageBased.Core
{
/// <summary>
/// TCP Server Class that work with Message structures.
/// </summary>
public class BaseMessageServer : Server
{
/// <summary>
/// Limit of user allowed inside the server.
/// </summary>
protected Int32 _userlimit;
/// <summary>
/// Delegate for the event of receiving a Message from a client.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="sender">Client sending the message.</param>
/// <param name="Mess">Message received.</param>
public delegate void MessageReceivedHandler(BaseMessageServer server, BaseMessageClientS sender, TCPMessage Mess);
/// <summary>
/// Occurs when a Message is received by the server.
/// </summary>
public event MessageReceivedHandler OnClientMessageReceived;
/// <summary>
/// Delegate for the event of sending a Message to a client.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="receiver">Client that will receive the message.</param>
/// <param name="Mess">Message to be sent.</param>
public delegate void MessageSentHandler(BaseMessageServer server, BaseMessageClientS receiver, TCPMessage Mess);
/// <summary>
/// Occurs when the server send a Message to a client.
/// </summary>
public event MessageSentHandler OnClientBeforeMessageSent;
/// <summary>
/// Occurs when the server send a Message to a client.
/// </summary>
public event MessageSentHandler OnClientAfterMessageSent;
/// <summary>
/// Get/set the limit of users allowed inside the server.
/// </summary>
public Int32 UserLimit
{
get { return _userlimit; }
set { _userlimit = value; }
}
/// <summary>
/// Base constructor of the class.
/// </summary>
public BaseMessageServer() : base()
{
OnClientBeforeConnect += new BeforeConnectedHandler(BaseMessageServer_OnClientBeforeConnect);
OnClientDataReceived += new DataCommunicationHandler(BaseMessageServer_OnDataReceived);
OnClientAfterDataSent += new DataCommunicationHandler(BaseMessageServer_OnDataSent);
_userlimit = 0;
}
/// <summary>
/// Kick the client if the server reached the maximum allowed number of clients.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="client">Client connecting to the server.</param>
/// <param name="args">Specify if the client should be accepted into the server.</param>
void BaseMessageServer_OnClientBeforeConnect(Server server, ClientS client, CancelArgs args)
{
if ((Clients.Count >= UserLimit) && (UserLimit != 0))
{
TCPMessage msg = new TCPMessage();
msg.MessageType = MessageType.MaxUsers;
((BaseMessageClientS)client).Send(msg);
args.Cancel = true;
}
}
/// <summary>
/// Trasform the line of data sent into a Message structure and raise
/// the event linked.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="receiver">Client that will receive the Message.</param>
/// <param name="Data">Line of data sent.</param>
void BaseMessageServer_OnDataSent(Server server, ClientS receiver, Data Data)
{
TCPMessage msg = null;
try
{
msg = TCPMessage.FromByteArray(Data.Message);
}
catch (Exception)
{
}
if (msg != null)
if (OnClientAfterMessageSent != null)
OnClientAfterMessageSent(this, (BaseMessageClientS)receiver, msg);
}
/// <summary>
/// Raise the OnClientBeforeMessageSent event.
/// </summary>
/// <param name="cl">Client that raised the event.</param>
/// <param name="msg">Message to be sent.</param>
internal void RaiseBeforeMessageSentEvent(ClientS cl, TCPMessage msg)
{
if (OnClientBeforeMessageSent != null)
OnClientBeforeMessageSent(this, (BaseMessageClientS)cl, msg);
}
/// <summary>
/// Trasform the line of data received into a Message structure and raise
/// the event linked.
/// </summary>
/// <param name="server">Server raising the event.</param>
/// <param name="sender">Client sending the data.</param>
/// <param name="Data">Line of data received.</param>
void BaseMessageServer_OnDataReceived(Server server, ClientS sender, Data Data)
{
TCPMessage msg = null;
try
{
msg = TCPMessage.FromByteArray(Data.Message);
}
catch (Exception)
{
}
if (msg != null)
if (OnClientMessageReceived != null)
OnClientMessageReceived(this, (BaseMessageClientS)sender, msg);
}
/// <summary>
/// Function that create the structure to memorize the client data.
/// </summary>
/// <param name="socket">Socket of the client.</param>
/// <returns>The structure in which memorize all the information of the client.</returns>
protected override ClientS CreateClient(TcpClient socket)
{
return new BaseMessageClientS(this, socket);
}
/// <summary>
/// Send a message to all clients in broadcast.
/// </summary>
/// <param name="Data">Message to be sent.</param>
public void Broadcast(TCPMessage Data)
{
base.Broadcast(new Data(Data.ToByteArray()));
}
}
}

View File

@ -0,0 +1,114 @@
/*
The MIT License
Copyright (c) 2008 Ferreri Alessio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace TCPLibrary.MessageBased.Core
{
/// <summary>
/// Message structure that contains all the information of the message exchanged between
/// Message driven server/client.
/// </summary>
[Serializable]
public class TCPMessage
{
/// <summary>
/// Message Type.
/// </summary>
private MessageType _messageType;
/// <summary>
/// Messages parameters.
/// </summary>
private List<object> _parameters;
/// <summary>
/// Get/set the message type.
/// </summary>
public MessageType MessageType
{
get { return _messageType; }
set { _messageType = value; }
}
/// <summary>
/// Get/set the message parameters.
/// </summary>
public List<object> Parameters
{
get { return _parameters; }
}
/// <summary>
/// Base constructor of the class.
/// </summary>
public TCPMessage()
{
_messageType = MessageType.Connect;
_parameters = new List<object>();
}
/// <summary>
/// Parse a string and create a Message structure.
/// </summary>
/// <param name="data">Raw data.</param>
/// <returns>Parsed message structure.</returns>
static public TCPMessage FromByteArray(byte[] data)
{
MemoryStream ms = new MemoryStream();
BinaryWriter sw = new BinaryWriter(ms);
sw.Write(data, 0, data.Length);
sw.Flush();
ms.Position = 0;
BinaryFormatter formatter = new BinaryFormatter();
TCPMessage msg = formatter.Deserialize(ms) as TCPMessage;
return msg;
}
/// <summary>
/// Trasform the structure into a String.
/// </summary>
/// <returns>The structure in a String format.</returns>
public byte[] ToByteArray()
{
MemoryStream ms = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, this);
ms.Position = 0;
return ms.ToArray();
}
}
public enum MessageType
{
Connect,
MaxUsers,
SizeDump
}
}