运用Smark.SocketAsyncs方便实现数据交互服务

 Smark.SocketAsyncs是通过SocketAsyncEventArgs对Socket进行包装的处理程序,暂时只封装了对Tcp的支持。以下是通过Smark.SocketAsyncs封装一个简单的数据交互服务。
1)制定基础数据传输描述
 实现消息转换适配器

 

代码

    
public class MessageAdapter:Smark.SocketAsyncs.IMessage
    {
        
public object Message
        {
            
get;
            
set;
        }
        
#region IMessage 成员
        
public void SaveData(Encoding coding, Smark.SocketAsyncs.SendBuffer buffer)
        {
            buffer.Write(Smark.Core.Functions.SerializeObject(Message));
            buffer.WriteRN();
        }
        
public void LoadData(Encoding coding, Smark.SocketAsyncs.ReceiveBuffer buffer)
        {
            
byte[] data = buffer.ToBytes();
            Message 
= Smark.Core.Functions.DeserializeObject(data);
        }
        
#endregion
    }

 

 

 适配器主要功能是对象和byte之前的转换.

 实现命令和返回类型描述

 

代码
    [Serializable]
    
public class Command
    {
        
        
public CommandType Type
        {
            
get;
            
set;
        }
        
private List<object> mParameters = new List<object>();
        
public List<object> Parameters
        {
            
get
            {
                
return mParameters;
            }
        }
        
public object this[int index]
        {
            
get
            {
                
return Parameters[index];
            }
        }
        
    }
    
public enum CommandType
    {
        ListEmployee,
        LoadEmployee
    }
    [Serializable]
    
public class Result
    {
        
public object Data { getset; }
        
public string ErrorMessage { getset; }
    }

 

 

2)服务端代码实现
 建立一个控制台程序,定义相关监听对象和启用服务

 

代码
            Functions.LogOutputToConsole = LogType.Track;
            
string dbstring = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=";
            dbstring 
+= Smark.Core.Functions.GetPath(typeof(Program).Assembly);
            dbstring 
+= "Northwind.mdb";
            DBContext.SetConnectionString(ConnectionType.Context1, dbstring);
            TcpServer
<TcpClient<EofAtEnter>> server = new TcpServer<TcpClient<EofAtEnter>>();
            server.ClientConnected 
+= (o, e) => {
                Functions.WriteLog(LogType.Track, 
typeof(Program), "{0} On Connected \t {1}", e.Client.Name,DateTime.Now);
            };
            server.ClientDisposed 
+= (o, e) => {
                Functions.WriteLog(LogType.Track, 
typeof(Program), "{0} On Disposed \t {1}", e.Client.Name,DateTime.Now);
            };
            server.ClientError 
+= (o, e) => {
                Functions.WriteLog(LogType.Track, 
typeof(Program), "{0} On Error:{1} \t {2}", e.Client.Name,e.Exception.Message, DateTime.Now);
            };
            server.ClientReceive 
+= (o, e) => {
                
try
                {
                   
                    Modules.Command cmd 
= (Modules.Command)Functions.DeserializeObject(e.Buffer.Data, e.Buffer.Count - 2);
                    Execute(cmd,e.Client);
                }
                
catch (Exception e_)
                {
                    Functions.WriteLog(LogType.Track, 
typeof(Program), "{0} Data Error:{1} \t {2}", e.Client.Name, e_.Message, DateTime.Now);
                    e.Client.Dispose();
                }
            };
            server.Open(Functions.AppSettingValue(
"ip"),Functions.AppSettingValue<int>("port"),100);
            Functions.WriteLog(LogType.Track, 
typeof(Program), "SocketAsyncsForNorthwind.ServerApp Start \t {0}",DateTime.Now);
            Console.Read();

 

 

 以上是构建一个Tcp服务,并以/r/n作为结束分析协议。

 命令分发和处理代码

 

代码
        static void Execute(Modules.Command cmd,ITcpClient client)
        {
            StringBuilder sb 
= new StringBuilder();
            sb.AppendLine(
"Execute Command:" + cmd.Type);
            
foreach(object item in cmd.Parameters)
            {
                sb.AppendFormat(
"Parameter:{0}\r\n", item);

            }
            
            Functions.WriteLog(LogType.Track, 
typeof(Program), sb.ToString());
            
switch (cmd.Type)
            {
                
case SocketAsyncsForNorthwind.Modules.CommandType.LoadEmployee:
                    LoadEmployee(cmd,client);
                    
break;
                
case SocketAsyncsForNorthwind.Modules.CommandType.ListEmployee:
                    ListEmployee(cmd, client);
                    
break;

            }
        }
        
static void ListEmployee(Modules.Command cmd, ITcpClient client)
        {
            Modules.Result resul 
= new SocketAsyncsForNorthwind.Modules.Result();
            
try
            {
                Expression exp 
= new Expression();
                
if (cmd.Parameters[0!= null)
                    exp 
&= Modules.Employees.firstName.Match(cmd[0]);
                
if (cmd[1!= null)
                    exp 
&= Modules.Employees.lastName.Match(cmd[0]);
                
if (cmd[2!= null)
                    exp 
&= Modules.Employees.region.Match(cmd[0]);
                resul.Data 
= exp.List<Modules.Employees>();
            }
            
catch (Exception e_)
            {
                resul.ErrorMessage 
= e_.Message;
            }
            SendData(resul, client);
        }
         
        
static void LoadEmployee(Modules.Command cmd,ITcpClient client)
        {
            Modules.Result resul 
= new SocketAsyncsForNorthwind.Modules.Result();
            
try
            {
                Modules.Employees employee 
= DBContext.Load<Modules.Employees>(cmd.Parameters[0]);
                resul.Data 
= employee;
            }
            
catch (Exception e_)
            {
                resul.ErrorMessage 
= e_.Message;
            }
            SendData(resul, client);
           

        }
        
static void SendData(object data, ITcpClient client)
        {
            Modules.MessageAdapter ma 
= new SocketAsyncsForNorthwind.Modules.MessageAdapter();
            ma.Message 
= data;
            client.Send(ma);
        }

 


3)客户端实调用处理
 客户端逻辑包装类
 由于Smark.SocketAsyncs是基于异步处理的,所以为了方便调用封装一个基本同步发送和接放的包装类。

 

 

代码
public class NorthWindClient:IDisposable
    {

        
private System.Threading.EventWaitHandle mHandler = new System.Threading.EventWaitHandle(false, System.Threading.EventResetMode.ManualReset);
        
private TcpClient<EofAtEnter> mClient;
        
public NorthWindClient(string ip, int port)
        {
            Init(ip, port);
        }
        
private void Init(string ip,int port)
        {
            mClient 
= TcpServer<TcpClient<EofAtEnter>>.CreateClient(ip, port);
            mClient.Receive();
            mClient.Error 
+= (o, e) => {
                Result 
= new Result();
                Result.ErrorMessage 
= e.Exception.Message;
                mHandler.Set();
            };
            mClient.DataReceive 
+= (o, e) => {
                
byte[] data = e.Buffer.ToBytes(0, e.Buffer.Count - 2);
                Result 
= (Modules.Result)Functions.DeserializeObject(data);
                mHandler.Set();
            };
        }
        
public Result Result
        {
            
get;
            
set;
        }
        
public IList<Employees> ListEmployees(string firstname, string lastname, string region)
        {
            Result 
= null;
            Modules.Command cmd 
= new Command();
            cmd.Type 
= CommandType.ListEmployee;
            cmd.Parameters.Add(firstname);
            cmd.Parameters.Add(lastname);
            cmd.Parameters.Add(region);
            
return (IList<Employees>)SendData(cmd);
        }
        
public Employees LoadEmployee(int id)
        {
            Result 
= null;
            Modules.Command cmd 
= new Command();
            cmd.Type 
= CommandType.LoadEmployee;
            cmd.Parameters.Add(id);
           
return (Employees) SendData(cmd);
           
           

        }
        
protected object SendData(object data)
        {
            
return SendData(data, 2000);
        }
        
protected object SendData(object data,int timeout)
        {
            Modules.MessageAdapter ma 
= new MessageAdapter();
            ma.Message 
= data;
            mClient.Send(ma);
            mHandler.Reset();
            mHandler.WaitOne(timeout);
            
if (Result == null)
            {
                
throw new Exception("超时!");
            }
            
else if (Result.ErrorMessage != null)
            {
                
throw new Exception(Result.ErrorMessage);
            }
            
return Result.Data;
        }
        
#region IDisposable 成员

        
public void Dispose()
        {
            
if (mClient != null)
                mClient.Dispose();
        }

        
#endregion
    }

 

 NorthWindClient功能在初始化的时候接入的服务器,每个逻辑在请求时挂起2秒等待处理,处理错误或超时返回异常。当接收到服务端处理完后取消挂起返回处理值。

 客户端UI处理代码


代码
    public partial class Form1 : Form
    {
        
private Modules.NorthWindClient Client;
        
public Form1()
        {
            InitializeComponent();
        }

        
private void Form1_Load(object sender, EventArgs e)
        {
            
try
            {
                Smark.SocketAsyncs.Utils.AsyncEventArgsPool_MAX 
= 10;
                Client 
= new SocketAsyncsForNorthwind.Modules.NorthWindClient(Functions.AppSettingValue("ip"), Functions.AppSettingValue<int>("port"));
                dataGridView1.DataSource 
= Client.ListEmployees(nullnullnull);
            }
            
catch (Exception e_)
            {
                MessageBox.Show(e_.Message);
            }
        }


        
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
        {
            
if (dataGridView1.SelectedRows.Count>0)
            {
                Modules.Employees emp 
= (Modules.Employees)dataGridView1.SelectedRows[0].DataBoundItem;
                propertyGrid1.SelectedObject 
= Client.LoadEmployee(emp.EmployeeID);
            }
        }

        
private void button1_Click(object sender, EventArgs e)
        {
            
try
            {
            dataGridView1.DataSource 
= Client.ListEmployees(textBox1.Text, textBox2.Text, textBox3.Text);
            }
            
catch (Exception e_)
            {
                MessageBox.Show(e_.Message);
            }
        }      
    }

 

相关程序代码:[url:https://smark.svn.codeplex.com/svn/Samples/SocketAsyncsForNorthwind/]

4)简单负载测试

  测试用例获取所有Employee数据

 

posted on 2010-06-23 12:27 henry 阅读(...) 评论(...) 编辑 收藏

导航

公告

统计