物理拓撲就不畫了,是一般簡單的CS架構
二,服務端實現過程
1), 服務端開始監聽,並啟動接收線程
public void Start(int port)
{
_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();
}
}
2), 接收線程的實現,按照上面的邏輯圖示,我們接收到連接后,就要實例連接對象,並注入監聽對象的服務對象
Console.WriteLine(Thread.CurrentThread.Name + "開始");
while (true)
{
Socket clientSocket = serverSocket.Accept();
_clientSocketList.Add(new SocketClientBase(_instanceList, clientSocket));
Console.WriteLine(Thread.CurrentThread.Name + "獲取到新的客戶端(" + clientSocket.RemoteEndPoint.ToString() + ")");
}
服務端的代碼就這么多,所有操作都是交給連接對象(SocketClientBase)去處理的
三,客戶端實現過程(連接對象)
1), 服務對象定義
[Serializable()]
public class ObjectInstance
{
/// <summary>
/// 實例KEY
/// </summary>
public string InstanceKey { get; set; }
/// <summary>
/// 實例
/// </summary>
public object Instance { get; set; }
}
2), Request消息和Response消息的實現
[Serializable()]
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
}
上面我定義遠程調用的方式的,和調用的約定對象,以及返回結果的定義
3),發送遠程調用消息
/// <summary>
/// 調用遠程方法
/// </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);
}
/// <summary>
/// 請求遠程主機
/// </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;
}
/// <summary>
/// 發送請求
/// </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());
}
4), 回復遠程調用,這里有兩種情況,一種是遠程主機發送過來的請求,另一種是遠程主機響應的請求的回發
a),消息為請求,我們就需要執行請求的內容,然后返回執行結果
private void ActionRequest(RequestMessage request)
{
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);
}
b),當消息為返回的請求結果
private void ActionResponse(ResponseMessage response)
{
if (OnGetReponseEvent != null)
OnGetReponseEvent(response);
}
測試代碼
/// <summary>
/// 應用程序的主入口點。
/// </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");
}
}
總結,這個實現模型,是基於一種旁注理念的,松耦合的實現方式,這個模型只是一個原型,沒有錯誤處理等其他一些外圍實現,我試驗過單客戶端IO性能大概48M,由於沒有設計線程池,所以只能小規模應用