您的位置:首页 > 理论基础 > 计算机网络

C# 小规模网络远程调用的基类(基于Socket方式)实现

2012-04-28 18:03 771 查看
一,程序逻辑图示
 



 

物理拓扑就不画了,是一般简单的CS架构

二,服务端实现过程

  1), 服务端开始监听,并启动接收线程
  

public void Start(int port)


[code]{


_listenPort = port;


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


serverSocket.Bind(new IPEndPoint(IPAddress.Any, port));


 


serverSocket.Listen(_backlog);


Console.WriteLine("端口侦听开始");


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


{


Thread acceptThread = new Thread(new ThreadStart(RecieveAccept));


acceptThread.Name = "接收" + (i + 1) + "号线程";


acceptThreadList.Add(acceptThread);


acceptThread.Start();


}


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

  2), 接收线程的实现,按照上面的逻辑图示,我们接收到连接后,就要实例连接对象,并注入监听对象的服务对象

 

Console.WriteLine(Thread.CurrentThread.Name + "开始");


[code]while (true)


{


Socket clientSocket = serverSocket.Accept();


_clientSocketList.Add(new SocketClientBase(_instanceList, clientSocket));


Console.WriteLine(Thread.CurrentThread.Name + "获取到新的客户端(" + clientSocket.RemoteEndPoint.ToString() + ")");


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

服务端的代码就这么多,所有操作都是交给连接对象(SocketClientBase)去处理的

三,客户端实现过程(连接对象)

1), 服务对象定义

 [Serializable()]


[code]public class ObjectInstance


{


/// <summary>


/// 实例KEY


/// </summary>


public string InstanceKey { get; set; }


/// <summary>


/// 实例


/// </summary>


public object Instance { get; set; }


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

2), Request消息和Response消息的实现

[Serializable()]


[code]abstract public class Message


{


abstract public MessageType MessageType { get; set; }


}

[Serializable()]


public class RequestMessage : Message


{


public RequestMessage(ActionType actionType, string instanceKey, string callName)


{


_requestKey = Guid.NewGuid().ToString();


ActionType = actionType;


InstanceKey = instanceKey;


CallName = callName;


}


private string _requestKey;


 


public string RequestKey


{


get { return _requestKey; }


private set { _requestKey = value; }


}


public DateTime SendTimeKey { get; set; }


public ActionType ActionType { get; private set; }


public string InstanceKey { get; private set; }


public string CallName { get; private set; }


public override MessageType MessageType


{


get


{


return Net.MessageType.Request;


}


set


{


throw new NotImplementedException();


}


}


 


public Object[] Parameters { get; set; }


}

[Serializable()]


public class ResponseMessage : Message


{


public ResponseMessage(string requestKey)


{


_requestKey = requestKey;


}


private string _requestKey;


 


public string RequestKey


{


get { return _requestKey; }


private set { _requestKey = value; }


}


 


public bool IsError { get; set; }


public XQException ErrorInfo { get; set; }


 


public object ReturnObject { get; set; }


public DateTime SendTimeKey { get; set; }


 


public override MessageType MessageType


{


get


{


return Net.MessageType.Response;


}


set


{


throw new NotImplementedException();


}


}


}

[Serializable()]


public enum ActionType


{


CallMethod = 0, CallProperty = 1, CallField = 4, Other = 8


}

[Serializable()]


public enum MessageType


{


Response = 0, Request = 1


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

上面我定义远程调用的方式的,和调用的约定对象,以及返回结果的定义

3),发送远程调用消息

 


/// <summary>


[code]/// 调用远程方法


/// </summary>


/// <param name="instanceKey"></param>


/// <param name="methodName"></param>


/// <param name="pars"></param>


/// <returns></returns>


public ResponseMessage CallRemoteMethod(string instanceKey, string methodName, params object[] pars)


{


var response = new RequestMessage(ActionType.CallMethod, instanceKey, methodName);


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


response.Parameters = pars;


return CallRemoteHost(response);


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

   

/// <summary>


[code]/// 请求远程主机


/// </summary>


/// <param name="request"></param>


/// <returns></returns>


public ResponseMessage CallRemoteHost(RequestMessage request)


{


ResponseMessage response = null;


var getResponse = new OnGetReponseHandler(delegate(ResponseMessage args)


{


if (args.RequestKey == request.RequestKey)


{


response = args;


}


});


this.OnGetReponseEvent += getResponse;


SendRequest(request);


DateTime beginTime = DateTime.Now;


while (true)


{


if (TimeSpan.FromTicks(DateTime.Now.Ticks - beginTime.Ticks).TotalMilliseconds > 60 * 1000)


{


this.OnGetReponseEvent -= getResponse;


return new ResponseMessage(request.RequestKey) { IsError = true, ErrorInfo = XQException.GetException(5565, "远程操作超时") };


}


if (response != null)


break;


}


this.OnGetReponseEvent -= getResponse;


return response;


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }


/// <summary>


[code]/// 发送请求


/// </summary>


/// <param name="request"></param>


private void SendRequest(RequestMessage request)


{


byte[] data = SerializationHelper.ToByte(request);


var streamData = SetStreamDataEnd(data);


int count = clientSocket.Send(streamData);


Console.WriteLine("发送数据到" + count + "字节数据到" + clientSocket.RemoteEndPoint.ToString());


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

4), 回复远程调用,这里有两种情况,一种是远程主机发送过来的请求,另一种是远程主机响应的请求的回发

a),消息为请求,我们就需要执行请求的内容,然后返回执行结果

 
private void ActionRequest(RequestMessage request)


[code]{


ResponseMessage response = new ResponseMessage(request.RequestKey);


Object instance = GetInstance(request.InstanceKey);


if (instance == null)


{


response.IsError = true;


response.ErrorInfo = XQException.GetException(5566, "实例不存在");


}


else


{


string callName = request.CallName;


switch (request.ActionType)


{


case ActionType.CallMethod:


var methodInfo = instance.GetType().GetMethod(callName);


if (methodInfo == null)


{


response.IsError = true;


response.ErrorInfo = XQException.GetException(5567, "方法不存在");


}


else


{


object result = methodInfo.Invoke(instance, request.Parameters);


response.ReturnObject = result;


}


break;


case ActionType.CallProperty:


var propertyInfo = instance.GetType().GetProperty(callName);


if (propertyInfo == null)


{


response.IsError = true;


response.ErrorInfo = XQException.GetException(5568, "属性不存在");


}


else


{


object result = propertyInfo.GetValue(instance, null);


response.ReturnObject = result;


}


break;


case ActionType.CallField:


var fieldInfo = instance.GetType().GetField(callName);


if (fieldInfo == null)


{


response.IsError = true;


response.ErrorInfo = XQException.GetException(5569, "字段不存在");


}


else


{


object result = fieldInfo.GetValue(instance);


response.ReturnObject = result;


}


break;


}


}


SendResponse(response);


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

b),当消息为返回的请求结果

   private void ActionResponse(ResponseMessage response)


[code]{


if (OnGetReponseEvent != null)


OnGetReponseEvent(response);


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

测试代码

  /// <summary>


[code]/// 应用程序的主入口点。


/// </summary>


[STAThread]


static void Main()


{


//Application.EnableVisualStyles();


//Application.SetCompatibleTextRenderingDefault(false);


//Application.Run(new Form1());


var serverInstance = new List<ObjectInstance>();


serverInstance.Add(new ObjectInstance() { InstanceKey = "Server-1", Instance = new Server() });


SocketServerBase sbServer = new SocketServerBase(serverInstance);


sbServer.Start(9999);


 


 


var clientInstance = new List<ObjectInstance>();


clientInstance.Add(new ObjectInstance() { InstanceKey = "client-1", Instance = new Client() });


SocketClientBase sbClient = new SocketClientBase(clientInstance);


sbClient.Connect(8888, "127.0.0.1", 9999);


 


 


 


Thread.Sleep(1000);


 


var client = sbServer.ClientSocketList.Find(p => p.RemoteIp == "127.0.0.1" && p.RemorePort == 8888);


StringBuilder sendText = new StringBuilder();


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


{


sendText.Append(text);


}


string strText = sendText.ToString();


sendText.Length = 0;


while (true)


{


var response = sbClient.CallRemoteMethod("Server-1", "Add");


response = sbClient.CallRemoteMethod("Server-1", "Add2", 1, 2);


response = sbClient.CallRemoteMethod("Server-1", "Add3", 1, 2);


response = sbClient.CallRemoteMethod("Server-1", "Add4", strText);


client.CallRemoteMethod("client-1", "Print", strText);


}


Console.ReadLine();


}




 


 


public class Server


{


public void Add()


{


Console.WriteLine("Server Add");


}


 


public void Add2(int x, int y)


{


Console.WriteLine("Server Add2");


}


 


public int Add3(int x, int y)


{


Console.WriteLine("Server Add3");


return 1;


}


public int Add4(string text)


{


Console.WriteLine("Server Add3");


return 1;


}


}


 


public class Client


{


public void Print(string text)


{


// Console.WriteLine(text);


Console.WriteLine("Client Print");


}


}

[/code]

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

总结,这个实现模型,是基于一种旁注理念的,松耦合的实现方式,这个模型只是一个原型,没有错误处理等其他一些外围实现,我试验过单客户端IO性能大概48M,由于没有设计线程池,所以只能小规模应用

,完整源代码/Files/Rolends/SocketBase.rar
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: