В ней подробно рассказывается как создавать удаленные объекты и вызывать их методы.
Само решение очень близко с COM out process взаимодействием на IDispatch.
Помню с удовольствием разбирался с внутренностями TSocketConnection.
Но, в отличие от Idispatch, используется перегрузка методов и операторов, вызов Generic методов с выводом типов или с заданием Generic аргументов.
Поддержка методов расширений для классов, находящихся в одной сборке и для Linq методов.
Также поддержка асинхронных методов и подписка на события, ref и out параметры, доступ по индексу [], поддержка итераторов в foreach.
В отличии от Web Api, не нужно писать специально серверный код Controller, Hub ы.
Это близко к AppDomain c Remouting но, в отличие от Remoting, каждый класс является аналогом MarshalByRefObject. То есть, мы можем создать любой объект на стороне сервера и вернуть ссылку на него (некоторые языки из чисел поддерживают только double).
При вызове методов, напрямую сериализуются параметры только следующих типов: числа, строки, дата, Guid и byte[]. Для остальных типов нужно их создать на стороне сервера, а в параметрах методов уже передаются ссылки на них.
и солнце б утром не вставало, когда бы не было меня
Но скорость вызова чуть больше 2000 вызовов в секунду. Даже не знаю это много или мало?
Вот клиент
public class AutoWrapClient : DynamicObject
{
public int Target;
IPEndPoint IpEndpoint;
public AutoWrapClient(int Target,IPEndPoint IpEndpoint)
{
// IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Parse(АдресСервера), порт);this.Target = Target;
this.IpEndpoint = IpEndpoint;
}
// вызов методаstatic public string LastError;
public static dynamic GetProxy(string ServerAddres, int port)
{
IPEndPoint ipEndpoint = new IPEndPoint(IPAddress.Parse(ServerAddres), port);
return new AutoWrapClient(0, ipEndpoint);
}
private BinaryReader SendMessage(MemoryStream stream)
{
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{ client.Connect(IpEndpoint);
using (var ns = new NetworkStream(client))
{
stream.Position = 0;
ns.Write(BitConverter.GetBytes((Int32)stream.Length), 0, 4);
stream.CopyTo(ns);
using (var br = new BinaryReader(ns))
{
var streamSize = br.ReadInt32();
var res = br.ReadBytes(streamSize);
var ms = new MemoryStream(res);
ms.Position = 0;
return new BinaryReader(ms);
}
}
}
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = null;
var ms = new MemoryStream();
var bw = new BinaryWriter(ms);
bw.Write((byte)CallMethod.CallFunc);
bw.Write(Target);
bw.Write(binder.Name);
bw.Write(args.Length);
foreach (var arg in args)
WorkVariants.WriteObject(arg, bw);
bw.Flush();
var res= SendMessage(ms);
var resRun = res.ReadBoolean();
var returnValue = WorkVariants.GetObject(res, IpEndpoint);
if (!resRun)
{
if (returnValue != null && returnValue.GetType() == typeof(string))
LastError = (string)returnValue;
return false;
}
result = returnValue;
// Error=AutoWrap.СообщитьОбОшибке("не найден дженерик тип "+ИмяМетода);return true;
}
}
И вызов
Console.OutputEncoding = System.Text.Encoding.UTF8;
//Process.Start
Console.WriteLine("Hello Client!");
var wrap = Client.AutoWrapClient.GetProxy("127.0.0.1", 6891);
int res = wrap.ReturnParam(3);
Console.WriteLine(res);
string str = wrap.ReturnParam("Hello"); // Возвращает параметр
Console.WriteLine(str);
Console.WriteLine(wrap.ReturnParam(3.14));
Console.WriteLine(wrap.ReturnParam(DateTime.Now));
decimal dc = 678.89M;
Console.WriteLine(dc);
var stopWatch = new System.Diagnostics.Stopwatch();
int count = 0;
stopWatch.Start();
for (int i = 0; i < 10000; i++)
{
count += wrap.ReturnParam(i);
}
stopWatch.Stop();
var ts = stopWatch.Elapsed;
var elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10, 0);
Console.WriteLine(count);
Console.WriteLine(elapsedTime);
Console.ReadLine();
и солнце б утром не вставало, когда бы не было меня
Ну судя по огромному количеству отзывов это осбо не нужно.
Пока реализовал такие вызовы
var wrap = Client.AutoWrapClient.GetProxy("127.0.0.1", 6891);
//ReturnParam просто возвращает переданный параметр
// Через него проверим отправку и возврат результатаint res = wrap.ReturnParam(3);
Console.WriteLine(res);
string str = wrap.ReturnParam("Привет");
Console.WriteLine(str);
Console.WriteLine(wrap.ReturnParam(3.14));
Console.WriteLine(wrap.ReturnParam(DateTime.Now));
decimal dc = 678.89M;
Console.WriteLine(dc);
var ba = new byte[10];
for (int i = 0; i < ba.Length; i++)
{
ba[i]=(byte)i;
}
byte[] baRes = wrap.ReturnParam(ba);
for (int i = 0; i < ba.Length; i++)
{
Console.Write(i+",");
}
Console.WriteLine("");
// Загрузим стороннюю сборку и получим из неё тип
// Сборка должна быть в директории сервераvar Тестовый = wrap.Тип("TestDllForCoreClr.Тестовый", "TestDll");
// На основании типа создадим объектvar TO = wrap.New(Тестовый,"Свойство из Конструктора");
// Получим свойство объекта
Console.WriteLine("Свойство Объекта " + TO.СвойствоОбъекта);
var EO = TO.ПолучитьExpandoObject();
Console.WriteLine("Свойство ExpandoObject Имя "+EO.Имя);
Console.WriteLine("Свойство ExpandoObject Число "+EO.Число);
int rs = TO.ПолучитьЧисло(89);
count = 0;
stopWatch.Restart();
for (int i = 0; i < 1000; i++)
{
count += TO.ПолучитьЧисло(i);
}
stopWatch.Stop();
То есть получаем реальный RPC/
Пока сериализуются напрямую
public class WorkVariants
{
internal static Dictionary<Type, EnumVar> СоответствиеТипов;
static WorkVariants()
{
СоответствиеТипов = new Dictionary<Type, EnumVar>()
{
{ typeof(Int16),EnumVar.VTYPE_I2 },
{typeof(Int32),EnumVar.VTYPE_I4 },
{typeof(float),EnumVar.VTYPE_R4 },
{typeof(double),EnumVar.VTYPE_R8 },
{typeof(bool),EnumVar.VTYPE_BOOL },
{typeof(sbyte),EnumVar.VTYPE_I1 },
{typeof(byte),EnumVar.VTYPE_UI1 },
{typeof(UInt16),EnumVar.VTYPE_UI2},
{typeof(UInt32),EnumVar.VTYPE_UI4},
{typeof(Int64),EnumVar.VTYPE_I8},
{typeof(UInt64),EnumVar.VTYPE_UI8},
{typeof(string),EnumVar.VTYPE_PWSTR},
{typeof(byte[]),EnumVar.VTYPE_BLOB},
{typeof(DateTime),EnumVar.VTYPE_DATE},
{typeof(AutoWrapClient),EnumVar.VTYPE_AutoWrap}//,
// {typeof(AutoWrap),EnumVar.VTYPE_JSObject}
};
}
public static DateTime ReadDateTime(BinaryReader stream)
{
long nVal = stream.ReadInt64();
//get 64bit binaryreturn DateTime.FromBinary(nVal);
}
public static void WriteDateTime(DateTime value,BinaryWriter stream)
{
long nVal = value.ToBinary();
//get 64bit binary
stream.Write(nVal);
}
public static byte[] ReadByteArray(BinaryReader stream)
{
var length = stream.ReadInt32();
return stream.ReadBytes(length);
}
public static object GetObject(BinaryReader stream, IPEndPoint IpEndpoint)
{
EnumVar тип =(EnumVar)stream.ReadByte();
switch (тип)
{
case EnumVar.VTYPE_EMPTY:
case EnumVar.VTYPE_NULL: return null;
case EnumVar.VTYPE_I2: return stream.ReadInt16();
case EnumVar.VTYPE_I4: return stream.ReadInt32();
case EnumVar.VTYPE_R4: return stream.ReadSingle();
case EnumVar.VTYPE_R8: return stream.ReadDouble();
case EnumVar.VTYPE_BOOL:return stream.ReadBoolean();
case EnumVar.VTYPE_I1: return stream.ReadSByte();
case EnumVar.VTYPE_UI1: return stream.ReadByte();
case EnumVar.VTYPE_UI2: return stream.ReadUInt16();
case EnumVar.VTYPE_UI4: return stream.ReadUInt32();
case EnumVar.VTYPE_I8: return stream.ReadInt64();
case EnumVar.VTYPE_UI8: return stream.ReadUInt64();
case EnumVar.VTYPE_PWSTR:
var str= stream.ReadString();
return str;
case EnumVar.VTYPE_BLOB:
return ReadByteArray(stream);
case EnumVar.VTYPE_DATE:
return ReadDateTime(stream);
case EnumVar.VTYPE_AutoWrap:
var Target= stream.ReadInt32();
var AW = new AutoWrapClient(Target, IpEndpoint);
return AW;
}
return null;
}
public static bool WriteObject(object Объект, BinaryWriter stream)
{
if (Объект == null)
{
stream.Write((Int16)EnumVar.VTYPE_NULL);
stream.Write((Int32)0);
return true;
}
EnumVar type;
var res = СоответствиеТипов.TryGetValue(Объект.GetType(), out type);
if (!res) return false;
stream.Write((byte)type);
switch (type)
{
case EnumVar.VTYPE_I2: stream.Write((Int16) Объект); break;
case EnumVar.VTYPE_I4: stream.Write((Int32)Объект); break;
case EnumVar.VTYPE_R4: stream.Write((float)Объект); break;
case EnumVar.VTYPE_R8: stream.Write((double)Объект); break;
case EnumVar.VTYPE_BOOL: stream.Write((bool)Объект); break;
case EnumVar.VTYPE_I1: stream.Write((sbyte)Объект); break;
case EnumVar.VTYPE_UI1: stream.Write((byte)Объект); break;
case EnumVar.VTYPE_UI2: stream.Write((UInt16)Объект); break;
case EnumVar.VTYPE_UI4: stream.Write((UInt32)Объект); break;
case EnumVar.VTYPE_I8: stream.Write((Int64)Объект); break;
case EnumVar.VTYPE_UI8: stream.Write((UInt64)Объект); break;
case EnumVar.VTYPE_PWSTR: stream.Write((string)Объект); break;
case EnumVar.VTYPE_BLOB: stream.Write((byte[])Объект); break;
case EnumVar.VTYPE_DATE: WriteDateTime((DateTime)Объект, stream); break;
case EnumVar.VTYPE_AutoWrap:
// УстановитьСтрокуВIntPtr(((AutoWrap)Объект).ПолучитьСсылку(), Элемент);
// Marshal.WriteInt16(текПоз, (Int16)EnumVar.VTYPE_PWSTR);
stream.Write(((AutoWrapClient)Объект).Target);
break;
}
return true;
}
}
Для ускорения можно вручную сериализовать и десериализовать в byte[]
Буду рад любым идеям и критике
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Tom, Вы писали:
S>>Но скорость вызова чуть больше 2000 вызовов в секунду. Даже не знаю это много или мало? Tom>Это настолько неприлично мало что не стоило писать вообще.
2000 вызовов в секунду это 2 вызова каждую миллисекунду, т.е. каждый вызов по 500 микросекунд. Почему Вы считаете, что в диалоговом режиме (вопрос-ответ) TCP/IP должен дать больше? Ведь латентность ОС на процесс и так измеряется в десятках миллисекунд.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Tom, Вы писали:
S>>Ну судя по огромному количеству отзывов это осбо не нужно. Tom>Сорри но это жесточайший треш, чем вам веб апи не подошёл?
А в чем треш? То есть RPC(Remoting),WCF это не треш?
Тот же COM out server тоже треш?
И кстати сколько выдает веб апи вызовов в секунду?
Еще раз это замена AppDomain и Remotig. Они то надеюсь не треш?
и солнце б утром не вставало, когда бы не было меня
S> А в чем треш? То есть RPC(Remoting),WCF это не треш?
Трэш
S>Тот же COM out server тоже треш?
Это не трэш, это разложившийся труп
S> И кстати сколько выдает веб апи вызовов в секунду?
Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте.
S> Еще раз это замена AppDomain и Remotig. Они то надеюсь не треш?
Какая нафиг замена, очнитесь О чём вы вообще.
AppDomain предназначены для изоляции кода и возможности по разному настраивать безопастность, для того что бы иметь возможность выгружать сборку, IPC и ремоутинг тут только для обеспечения этих возможностей. Какой смысл в вашем IPC без реальных фич App Domain
Здравствуйте, Tom, Вы писали:
S>> А в чем треш? То есть RPC(Remoting),WCF это не треш? Tom>Трэш
S>>Тот же COM out server тоже треш? Tom>Это не трэш, это разложившийся труп
Угу а веб сервера это тот же труп только по другим протоколам.
S>> И кстати сколько выдает веб апи вызовов в секунду? Tom>Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте.
Ну ты же говоришь, что это медленно, значит у тебя есть замеры?
Ну дык подскажи как для .Net Core Pipelines использовать. Буду благодарен.
S>> Еще раз это замена AppDomain и Remotig. Они то надеюсь не треш? Tom>Какая нафиг замена, очнитесь О чём вы вообще. Tom>AppDomain предназначены для изоляции кода и возможности по разному настраивать безопастность, для того что бы иметь возможность выгружать сборку, IPC и ремоутинг тут только для обеспечения этих возможностей. Какой смысл в вашем IPC без реальных фич App Domain
А какие фичи App Domain
Можно запустить процесс, передать в параметрах номер порта, настроить безопасность. В чем отличие?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Tom, Вы писали:
S>>Ясно и приложения должны обмениваться исключительно через HTTP сервисы и SignalR? Tom>Причём тут SignalR вообще
А как ты события передавать будешь?
Tom>Если вас ваше решение устраивает оно для вас белое пушистое и быстрое то пусть так и будет.
Так я хочу получить советы. Как сделать так, что бы это устраивало не только меня одного.
и солнце б утром не вставало, когда бы не было меня
Tom>>Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте. S>Ну ты же говоришь, что это медленно, значит у тебя есть замеры?
Посмотри тесты techempower, даже код который в базу лезет работает на 2 порядка быстрее.
Не говоря о plaintext
S> Ну дык подскажи как для .Net Core Pipelines использовать. Буду благодарен. https://github.com/davidfowl/PipelinesSample
S>Можно запустить процесс, передать в параметрах номер порта, настроить безопасность. В чем отличие?
Во всём, глупая дискуссия.
ЗЫ: В упор не понимаю что и зачем ты делаешь. Сделать быстрый IO framework у тебя не получится, повторить функционал AppDomain тем более, тогда вопрос что вообще ты хочешь добиться.
ЗЫЫЫ: Если надо просто вызывать удалённый процесс — посмотри на grpc
Здравствуйте, Tom, Вы писали:
Tom>>>Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте. S>>Ну ты же говоришь, что это медленно, значит у тебя есть замеры? Tom>Посмотри тесты techempower, даже код который в базу лезет работает на 2 порядка быстрее. Tom>Не говоря о plaintext
S>> Ну дык подскажи как для .Net Core Pipelines использовать. Буду благодарен. Tom>https://github.com/davidfowl/PipelinesSample
Ок посмотрю. Спасибо. Сейчас сделаю на Tcp/Ip потом возьмусь за PipelinesSample
S>>Можно запустить процесс, передать в параметрах номер порта, настроить безопасность. В чем отличие? Tom>Во всём, глупая дискуссия.
Tom>ЗЫ: В упор не понимаю что и зачем ты делаешь. Сделать быстрый IO framework у тебя не получится, повторить функционал AppDomain тем более, тогда вопрос что вообще ты хочешь добиться.
Ну раз ты говоришь о том что пайпы на два порядка выше, то есть 200к вызовов в секунду, то это оочень быстрый Фреймворк.
Tom>ЗЫЫЫ: Если надо просто вызывать удалённый процесс — посмотри на grpc
Спасибо посмотрю.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Tom, Вы писали:
S>> Ок посмотрю. Спасибо. Сейчас сделаю на Tcp/Ip потом возьмусь за PipelinesSample Tom>Я бы grpc в первую очередь смотрел
У меня уже сделан через рефлексию вызов удаленных методов аналогичных C#.
То есть поддержка методов с params, с дефолтными параметрами, вызов дженерик методов итд.
То есть ты работаешь с удаленным объектом как со своим.
То есть, можно вызывать методы асинхронно
var wrap = Client.AutoWrapClient.GetProxy("127.0.0.1", 6891); // Получили удаленный объект
Можно создавать объекты из сборки в каталоге сервера
var Тестовый = wrap.Тип("TestDllForCoreClr.Тестовый", "TestDll");// TestDll в каталоге сервераvar TO = wrap.New(Тестовый,"Свойство из Конструктора");
Console.WriteLine("Свойство Объекта " + TO.СвойствоОбъекта);
TO.СвойствоОбъекта = "Свойство Новое";
Console.WriteLine("Свойство Объекта " + TO.СвойствоОбъекта);
var EO = TO.ПолучитьExpandoObject();
Console.WriteLine("Свойство ExpandoObject Имя "+EO.Имя);
Console.WriteLine("Свойство ExpandoObject Число "+EO.Число);
То есть код сервера можно не менять, только подсовывать нужные DLL, и создавать из них нужные объекты или вызывать статические методы.
Подключаться к событиям.
Это очень схоже с AppDamain
Здравствуйте, Tom, Вы писали:
S>> А в чем треш? То есть RPC(Remoting),WCF это не треш? Tom>Трэш
S>>Тот же COM out server тоже треш? Tom>Это не трэш, это разложившийся труп
Которым пользуется куча 1С и иже с ними.
При этом при переходе на 64 разрядную платформу, люди стали возвращаться обратно, так как in process повально 32 разрядные.
WCF я и сейчас пользуюсь с named pipes binding . Но в .Net Core нет, и при этом мою приблуду проще использовать.
Нужна любая сборка.
S>> И кстати сколько выдает веб апи вызовов в секунду? Tom>Посчитайте, возтмите тот же пример веб сервера на Pipelines и замеряйте.
Вот появятся named pipes в .Net Core на уровне сокетов обязательно проверю.
S>> Еще раз это замена AppDomain и Remotig. Они то надеюсь не треш? Tom>Какая нафиг замена, очнитесь О чём вы вообще. Tom>AppDomain предназначены для изоляции кода и возможности по разному настраивать безопастность, для того что бы иметь возможность выгружать сборку, IPC и ремоутинг тут только для обеспечения этих возможностей. Какой смысл в вашем IPC без реальных фич App Domain
Все фичи App Domain есть. Можно управлять и секьюрностью и выгружать и создавать любой объект и вызывать его.
Какие еще нужны фичи?
Code Access Security isn't and won't be available in .Net Core. Since all code is effectively running under full trust, it should be enough to remove those attributes.
If you actually want to restrict some code, the recommandation is:
Use operating system provided security boundaries, such as user accounts for running processes with the least set of privileges.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
К сожалению C# не поддерживает вызов new для TryCreateInstance DinamicObject
Сейчас объект создается так
var Тестовый = wrap.Тип("TestDllForCoreClr.Тестовый", "TestDll");
// На основании типа создадим объектvar TO = wrap.New(Тестовый,"Свойство из Конструктора");
То есть мы не можем вызвать используя DinamicObject и TryCreateInstance
var TO = new Тестовый("Свойство из Конструктора");
Но можно и так
var TO = Тестовый.new("Свойство из Конструктора");
Еще один вариант это использовать
TryInvoke(): вызов объекта в качестве делегата
var TO = Тестовый($$,"Свойство из Конструктора");
где $$ константная строка для сравнения Object.ReferenceEquals
и солнце б утром не вставало, когда бы не было меня
Я прекрасно понимаю, что это никому не нужно. Но нужно доделать.
Сил вложено немало. В итоге получилось поделие даже не хуже WCF.
А по мне даже и лучше. Больше возможностей. И при этом можне не писать серверный код.
Очень близко к AppDomain, только все объекты являются MarshalByRefObject.
Поэтому прошу совета помочь оформить и покритиковать.
Что сейчас есть.
Можно подключиться к существующему серверу или запустить процесс по известному пути
if (LoadLocalServer)
{
// connector = ClientRPC.TCPClientConnector.LoadAndConnectToLocalServer(GetParentDir(dir, 4) + $@"\Server\Server\bin\Release\netcoreapp1.1\Server.dll");
connector = ClientRPC.TCPClientConnector.LoadAndConnectToLocalServer(GetParentDir(dir, 4) + $@"\Server\Server\bin\Debug\netcoreapp1.1\Server.dll");
}
else
{
connector = new ClientRPC.TCPClientConnector("127.0.0.1", port);
// Нужен для асинхронных методов и Событий
// Если их нет то и смысла слушать порт нет
port = ClientRPC.TCPClientConnector.GetAvailablePort(6892);
connector.Open(port, 2);
}
После подключения можно получить типы и создавать объекты из сборок находящиеся в папке сервера и в паках CoreClr
Поддержка статических и объектных методов, Дженерик методов с выводом типа, с дженерик аргуметами, индесаторов, итераторов
Поддержка асинхронных методов и событий. Поддержка ref и out параметров
Например
static async Task<object> GetGenericAsyncResult(dynamic TO)
{
//public async Task<V> GenericMethodAsync<K, V>(K param, string param4 = "Test")object resTask = await TO.async.GenericMethodAsync(new object[] { "System.Int32", "System.String" }, 44);
return resTask;
}
static void TestGenericMethods(ClientRPC.TCPClientConnector connector)
{
Dictionary<int, string> ClientDict = new Dictionary<int, string>()
{
[1] = "Один",
[2] = "Второй2",
[3] = "Один3"
};
var @Dictionary2 = wrap.GetType("System.Collections.Generic.Dictionary`2", "System.Collections");
var @DictionaryIntString = wrap.GetGenericType(@Dictionary2, "System.Int32", "System.String");
// Скопируем словарь на сервер
// Закомментированы различные варианты
// var dict = connector.CoryTo(@DictionaryIntString, ClientDict);
// var dict = connector.CoryTo("System.Collections.Generic.Dictionary`2[System.Int32, System.String]", ClientDict);
// Скопируем словарь на серверvar dict = connector.CoryTo(ClientDict);
Console.WriteLine(wrap.toString(dict));
Console.WriteLine(dict[2]);
// Получим тип из сборки TestDllvar @TestClass = wrap.GetType("TestDllForCoreClr.TestClass", "TestDll");
// Создадим объект на сервере используя метод _newvar TO = @TestClass._new("Property from Constructor");
// Test асинхронного вызова дженерик методаvar resGM = GetGenericAsyncResult(TO).Result;
Console.WriteLine("Вызов дженерик метода с аргументами типов async " + resGM);
// Вызовем дженерик метод с автовыводом типа
// public T GenericMethod<V, T>(V param1, T param2, V param3)
resGM = TO.GenericMethod(dict, 99, "Hello");
Console.WriteLine("Вызов дженерик метода с выводом типа " + resGM);
// Test Generic Method с параметрами по умолчанию
//public string GenericMethodWithDefaulParam<K, V>(Dictionary<K, V> param1, K param2, int param3 = 4, string param4 = "Test")var @Int32 = wrap.GetType("System.Int32");
resGM = TO.GenericMethodWithDefaulParam(dict, 99);
Console.WriteLine("Вызов дженерик метода с автовыводом типов " + resGM);
resGM = TO.GenericMethodWithDefaulParam(pp(@Int32, "System.String"), dict, 99);
Console.WriteLine("Вызов дженерик метода с аргументами типов " + resGM);
// Test Generic Method с параметрами массивом
// public string GenericMethodWithParams<K, V>(Dictionary<K, V> param1, K param2, params string[] args)
resGM = TO.GenericMethodWithParams(dict, 99, "First", "Second");
Console.WriteLine("Вызов дженерик метода с автовыводом типов " + resGM);
resGM = TO.GenericMethodWithParams(pp(@Int32, "System.String"), dict, 99, "First", "Second");
Console.WriteLine("Вызов дженерик метода с аргументами типов " + resGM);
// public V GenericMethodWithRefParam<К,V >(К param, V param2, ref string param3)var OutParam = new ClientRPC.RefParam("TroLoLo");
resGM = TO.GenericMethodWithRefParam(5, "GenericMethodWithRefParam", OutParam);
Console.WriteLine($@"Вызов дженерик метода с автовыводом типов Ref {resGM} {OutParam.Value}");
var GenericArgs = new object[] { "System.String", "System.String" };
resGM = TO.GenericMethodWithRefParam(GenericArgs, null, "GenericMethodWithRefParam", OutParam);
Console.WriteLine($@"Вызов дженерик метода с дженерик аргументами Ref {resGM} {OutParam.Value}");
// Test return null
resGM = TO.GenericMethodWithRefParam(GenericArgs, null, null, OutParam);
Console.WriteLine($@"Вызов дженерик метода с дженерик аргументами Ref {resGM} {OutParam}");
}
Напрямую сериализуются byte[],числа, строки,булево,Дата,char,Guid
Для AutoWrapClient передается индекс в хранилище
Но можно скопировать данные на сервер и получить ссылку
var dict = connector.CoryTo(ClientDict);
Внутри используеся Json сериализация
// Сериализуем объект и отправим представление типа ввиде AssemblyQualifiedNamepublic dynamic CoryTo(object obj)
{
string type = obj.GetType().AssemblyQualifiedName;
var str = JsonConvert.SerializeObject(obj);
return CoryTo(type, str);
}
При этом мы можем получить и ссылку на byte[], так при обычном методе он сериализуется.
Но для этого нужно загрузить все используемы сборки.
static void TestSerializeObject(ClientRPC.TCPClientConnector connector)
{
// Получим на клиенте объект и скопируем его на серверvar obj = new TestDllForCoreClr.TestClass("Объект на стороне Клиента");
dynamic test = null;
try
{
test = connector.CoryTo(obj);
}
catch (Exception)
{
Console.WriteLine("Ошибка " + connector.LastError);
var assembly = wrap.GetAssembly("TestDll");
test = connector.CoryTo(obj);
}
Console.WriteLine(test.ObjectProperty);
}
Поддержка индексаторов и итераторов.
string[] sa = new string[] { "Нулевой", "Первый", "Второй", "Третий", "Четвертый" };
var ServerSA = connector.ArrayCoryTo("System.String", sa);
Console.WriteLine("ServerSA[2] " + ServerSA[2]);
ServerSA[2] = "Изменен Параметр по индексу 2";
Console.WriteLine("ServerSA[2] " + ServerSA[2]);
foreach (string value in ServerSA)
Console.WriteLine("Values " + value);
var Dictionary2 = wrap.GetType("System.Collections.Generic.Dictionary`2", "System.Collections");
var DictionaryIntString = wrap.GetGenericType(Dictionary2, "System.Int32", "System.String");
//var dict = wrap.New(DictionaryIS);
Dictionary<int, string> ClientDict = new Dictionary<int, string>()
{
[1] = "Один",
[2] = "Второй2",
[3] = "Один3"
};
foreach (string value in ServerSA)
Console.WriteLine("Values " + value);
Console.WriteLine("new " + DictionaryIntString._new());
// Можно просто connector.CoryTo(ClientDict);
// Но бывает что тип только на сервере. На клиенте такого типа нет
//Но можно использоварть ExpandoObject или JObjectvar dict = connector.CoryTo(DictionaryIntString, ClientDict);
Console.WriteLine("dict[2] " + dict[2]);
dict[2] = "Два";
Console.WriteLine("dict[2] " + dict[2]);
// используем класс ClientRPC.RefParam для получения измененного параметра.var OutParam = new ClientRPC.RefParam();
if (dict.TryGetValue(2, OutParam))
{
Console.WriteLine("OutParam " + OutParam.Value);
}
Вобщем отличие от родного кода это в вызове асинхронного метода за счет добавления слова async
Для вызова дженерик метода с дженерик аргуметами первым параметром должен идти массив типов
// public V GenericMethodWithRefParam<К,V >(К param, V param2, ref string param3)var OutParam = new ClientRPC.RefParam("TroLoLo");
var GenericArgs = new object[] { "System.String", "System.String" };
resGM = TO.GenericMethodWithRefParam(GenericArgs, null, "GenericMethodWithRefParam", OutParam);
Ну и подключение к эвентам
static public void EventWithTwoParameter(dynamic value)
{
Console.WriteLine("EventWithTwoParameter" + wrap.toString(value));
value(ClientRPC.AutoWrapClient.FlagDeleteObject);
}
// параметр value:System.Stringstatic public void EventWithOneParameter(dynamic value)
{
Console.WriteLine("EventWithOneParameter " + wrap.toString(value));
}
static public void EventWithOutParameter(dynamic value)
{
Console.WriteLine("EventWithOutParameter" + wrap.toString(value));
}
static void RunTestEvent(ClientRPC.TCPClientConnector connector)
{
var EventTest = wrap.GetType("TestDllForCoreClr.EventTest", "TestDll");
// var test = wrap.New(EventTest);var test = EventTest._new();
var wrapForEvents = connector.CreateWrapperForEvents(test);
wrapForEvents.AddEventHandler("EventWithTwoParameter", new Action<dynamic>(EventWithTwoParameter));
wrapForEvents.AddEventHandler("EventWithOneParameter", new Action<dynamic>(EventWithOneParameter));
wrapForEvents.AddEventHandler("EventWithOutParameter", new Action<dynamic>(EventWithOutParameter));
test.Run();
}
Основное отличие от WCF это использование DynamicObjet. Но можно тестировать код напрямую, а затем
приспосабливать его к PPC
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Кто о чем, а вшивый о бане.
S> Сейчас в .Net Core нет AppDomain и RPC .
Я бы использовал Protobuf + как там принято в .NET Core сообщения передавать между процессами. Никакой рефлексии, магии аля MarshalByRefObject и граблей с маршаллингом того, что не предназначено для маршаллинга.
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, Serginio1, Вы писали:
S>>Кто о чем, а вшивый о бане.
S>> Сейчас в .Net Core нет AppDomain и RPC .
H>Я бы использовал Protobuf + как там принято в .NET Core сообщения передавать между процессами. Никакой рефлексии, магии аля MarshalByRefObject и граблей с маршаллингом того, что не предназначено для маршаллинга.
А какая огромная разница между Protobuf и Json?
Для JSON есть прекрасная библиотека
Угу а сервер кто писать будет? Вся прелесть в том, что серверную часть тебе даже писать не надо. А сериализовать объекты тебе так или иначе нужно. А затраты на рефлексию при межпроцессном взаимодействии просто ничтожны.
Да а что тебе не нравится в моей разработке. Почему Protobuf лучше?
Граблей с маршалингом нет, затраты на рефлексию можно не рассматривать при этом все происходит автоматически.
И код мало отличается от работы с объектами напрямую.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>Угу а сервер кто писать будет? Вся прелесть в том, что серверную часть тебе даже писать не надо.
Ну вот тут уже надо смотреть что доступно в корке для общения со внешним миром. Написать один раз TCP-сервер и клиент с пулом соединений не очень трудно.
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, Serginio1, Вы писали:
S>> А какая огромная разница между Protobuf и Json? S>>Для JSON есть прекрасная библиотека
H>Сообщения протокола известны статически. Непонятно какие типы не уйдут в сеть и не придут внезапно из сети.
Ну опять же тебе нужно писать сервер. При моем подходе писать сервер не надо. Загружаешь нужные сборки и работаешь с ними удаленного.
Я понимаю, что web Api наше все. А как с асинхронными методами, событиями?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, Serginio1, Вы писали:
S>>Угу а сервер кто писать будет? Вся прелесть в том, что серверную часть тебе даже писать не надо.
H>Ну вот тут уже надо смотреть что доступно в корке для общения со внешним миром. Написать один раз TCP-сервер и клиент с пулом соединений не очень трудно.
Так он написан. Через него и происходит общение.
namespace ClientRPC
{
public enum EnumVar:byte
{
VTYPE_EMPTY = 0,
VTYPE_NULL,
VTYPE_I2, //int16
VTYPE_I4, //int32
VTYPE_R4, //float
VTYPE_R8, //double
VTYPE_Decimal, //Decimal
VTYPE_DATE, //DATE (double)
VTYPE_BOOL, //bool
VTYPE_I1, //int8
VTYPE_UI1, //uint8
VTYPE_UI2, //uint16
VTYPE_UI4, //uint32
VTYPE_I8, //int64
VTYPE_UI8, //uint64
VTYPE_INT, //int Depends on architecture
VTYPE_CHAR, //char
VTYPE_PWSTR, //struct wstr
VTYPE_BLOB, //means in struct str binary data contain
VTYPE_GUID, //Guid
VTYPE_AutoWrap, // Net Object
VTYPE_JSObject
};
// Класс WorkVariants осуществляет сериализацию и десериализацию объектовpublic class WorkVariants
{
internal static Dictionary<Type, EnumVar> MatchTypes;
static WorkVariants()
{
// Напрямую сериализуются byte[],числа, строки,булево,Дата,char,Guid
//Для AutoWrapClient передается индекс в хранилище
MatchTypes = new Dictionary<Type, EnumVar>()
{
{ typeof(Int16),EnumVar.VTYPE_I2 },
{typeof(Int32),EnumVar.VTYPE_I4 },
{typeof(float),EnumVar.VTYPE_R4 },
{typeof(double),EnumVar.VTYPE_R8 },
{typeof(decimal),EnumVar.VTYPE_Decimal},
{typeof(bool),EnumVar.VTYPE_BOOL },
{typeof(sbyte),EnumVar.VTYPE_I1 },
{typeof(byte),EnumVar.VTYPE_UI1 },
{typeof(UInt16),EnumVar.VTYPE_UI2},
{typeof(UInt32),EnumVar.VTYPE_UI4},
{typeof(Int64),EnumVar.VTYPE_I8},
{typeof(UInt64),EnumVar.VTYPE_UI8},
{typeof(char),EnumVar.VTYPE_CHAR},
{typeof(string),EnumVar.VTYPE_PWSTR},
{typeof(byte[]),EnumVar.VTYPE_BLOB},
{typeof(DateTime),EnumVar.VTYPE_DATE},
{typeof(AutoWrapClient),EnumVar.VTYPE_AutoWrap},
{typeof(Guid),EnumVar.VTYPE_GUID}//,
// {typeof(AutoWrap),EnumVar.VTYPE_JSObject}
};
}
public static DateTime ReadDateTime(BinaryReader stream)
{
long nVal = stream.ReadInt64();
//get 64bit binaryreturn DateTime.FromBinary(nVal);
}
public static void WriteDateTime(DateTime value,BinaryWriter stream)
{
long nVal = value.ToBinary();
//get 64bit binary
stream.Write(nVal);
}
public static byte[] ReadByteArray(BinaryReader stream)
{
var length = stream.ReadInt32();
return stream.ReadBytes(length);
}
public static object GetObject(BinaryReader stream, TCPClientConnector Connector)
{
// Считываем тип объекта
EnumVar type =(EnumVar)stream.ReadByte();
// В зависмости от типа считываем и преобразуем данныеswitch (type)
{
case EnumVar.VTYPE_EMPTY:
case EnumVar.VTYPE_NULL: return null;
case EnumVar.VTYPE_I2: return stream.ReadInt16();
case EnumVar.VTYPE_I4: return stream.ReadInt32();
case EnumVar.VTYPE_R4: return stream.ReadSingle();
case EnumVar.VTYPE_R8: return stream.ReadDouble();
case EnumVar.VTYPE_Decimal: return stream.ReadDecimal();
case EnumVar.VTYPE_BOOL: return stream.ReadBoolean();
case EnumVar.VTYPE_I1: return stream.ReadSByte();
case EnumVar.VTYPE_UI1: return stream.ReadByte();
case EnumVar.VTYPE_UI2: return stream.ReadUInt16();
case EnumVar.VTYPE_UI4: return stream.ReadUInt32();
case EnumVar.VTYPE_I8: return stream.ReadInt64();
case EnumVar.VTYPE_UI8: return stream.ReadUInt64();
case EnumVar.VTYPE_CHAR: return stream.ReadChar();
case EnumVar.VTYPE_PWSTR: return stream.ReadString();
case EnumVar.VTYPE_BLOB: return ReadByteArray(stream);
case EnumVar.VTYPE_DATE: return ReadDateTime(stream);
case EnumVar.VTYPE_GUID: return new Guid(stream.ReadBytes(16));
case EnumVar.VTYPE_AutoWrap:
var Target= stream.ReadInt32();
var AW = new AutoWrapClient(Target, Connector);
return AW;
}
return null;
}
public static bool WriteObject(object Объект, BinaryWriter stream)
{
// Если null то записываем только VTYPE_NULLif (Объект == null)
{
stream.Write((byte)EnumVar.VTYPE_NULL);
return true;
}
// Если это RefParam то сериализуем значение из Value
// Нужен для возвращения out значения в Value if (Объект.GetType() == typeof(RefParam))
{
object value= ((RefParam)Объект).Value;
return WriteObject(value, stream);
}
EnumVar type;
// Ищем тип в словаре MatchTypesvar res = MatchTypes.TryGetValue(Объект.GetType(), out type);
// Если тип не поддерживаемый вызываем исключениеif (!res) {
throw new Exception("Неверный тип " + Объект.GetType().ToString());
return false;
}
// Записываем тип объекта
stream.Write((byte)type);
// В зависимости от типа сериализуем объектswitch (type)
{
case EnumVar.VTYPE_I2: stream.Write((Int16)Объект); break;
case EnumVar.VTYPE_I4: stream.Write((Int32)Объект); break;
case EnumVar.VTYPE_R4: stream.Write((float)Объект); break;
case EnumVar.VTYPE_R8: stream.Write((double)Объект); break;
case EnumVar.VTYPE_Decimal: stream.Write((decimal)Объект); break;
case EnumVar.VTYPE_BOOL: stream.Write((bool)Объект); break;
case EnumVar.VTYPE_I1: stream.Write((sbyte)Объект); break;
case EnumVar.VTYPE_UI1: stream.Write((byte)Объект); break;
case EnumVar.VTYPE_UI2: stream.Write((UInt16)Объект); break;
case EnumVar.VTYPE_UI4: stream.Write((UInt32)Объект); break;
case EnumVar.VTYPE_I8: stream.Write((Int64)Объект); break;
case EnumVar.VTYPE_UI8: stream.Write((UInt64)Объект); break;
case EnumVar.VTYPE_CHAR: stream.Write((char)Объект); break;
case EnumVar.VTYPE_PWSTR: stream.Write((string)Объект); break;
case EnumVar.VTYPE_BLOB: stream.Write((byte[])Объект); break;
case EnumVar.VTYPE_DATE: WriteDateTime((DateTime)Объект, stream); break;
case EnumVar.VTYPE_GUID: stream.Write(((Guid)Объект).ToByteArray()); break;
case EnumVar.VTYPE_AutoWrap:
stream.Write(((AutoWrapClient)Объект).Target);
break;
}
return true;
}
}
}
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, Serginio1, Вы писали:
S>>Угу а сервер кто писать будет? Вся прелесть в том, что серверную часть тебе даже писать не надо.
H>Ну вот тут уже надо смотреть что доступно в корке для общения со внешним миром. Написать один раз TCP-сервер и клиент с пулом соединений не очень трудно.
Здравствуйте, Serginio1, Вы писали:
S> А какая огромная разница между Protobuf и Json?
Производительность.
S>Для JSON есть прекрасная библиотека
Нашел новую игрушку? Увы, но для остальных это не аргумент.
S>Граблей с маршалингом нет, затраты на рефлексию
Затраты на рефлексию, по результатам реальных замеров, это 90% всей работы при передаче по ip. При передаче по более быстрым каналам, особенно по CrossAppDomainChannel цифра вообще близка к 100%.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>Сил вложено немало. В итоге получилось поделие даже не хуже WCF.
AVK>Хуже, причем сильно хуже. Ты просто не понимаешь что такое WCF.
Которого нет Net Core.
А конструктивная критика?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>> А какая огромная разница между Protobuf и Json?
AVK>Производительность.
При межпроцессном взаимодействии разница ничтожна. S>>Для JSON есть прекрасная библиотека
AVK>Нашел новую игрушку? Увы, но для остальных это не аргумент.
S>>Граблей с маршалингом нет, затраты на рефлексию
AVK>Затраты на рефлексию, по результатам реальных замеров, это 90% всей работы при передаче по ip. При передаче по более быстрым каналам, особенно по CrossAppDomainChannel цифра вообще близка к 100%.
Угу. При внутрипроссном взаимодействии 500 000 вызовов в секунду
В том же CEF при взаимодействии между JS кодом нативои и .Net Core 60 000 вызовов в секунду.
А по TCP всего 2000 вызовов в секунду.
Здравствуйте, Serginio1, Вы писали:
H>>Сообщения протокола известны статически. Непонятно какие типы не уйдут в сеть и не придут внезапно из сети.
S>Ну опять же тебе нужно писать сервер. При моем подходе писать сервер не надо. Загружаешь нужные сборки и работаешь с ними удаленного.
S>Я понимаю, что web Api наше все. А как с асинхронными методами, событиями?
У меня пока не стоит задача удаленного взаимодействия в .Net Core, но когда встанет, я буду смотреть в сторону Protobuf + MQ фреймворк, типа ZeroMQ или RabbitMQ. Но не исключено, чот сделаю свой велосипед на общей памяти вместо TCP/IP.
Здравствуйте, hardcase, Вы писали:
H>Здравствуйте, Serginio1, Вы писали:
H>>>Сообщения протокола известны статически. Непонятно какие типы не уйдут в сеть и не придут внезапно из сети.
S>>Ну опять же тебе нужно писать сервер. При моем подходе писать сервер не надо. Загружаешь нужные сборки и работаешь с ними удаленного.
S>>Я понимаю, что web Api наше все. А как с асинхронными методами, событиями?
H>У меня пока не стоит задача удаленного взаимодействия в .Net Core, но когда встанет, я буду смотреть в сторону Protobuf + MQ фреймворк, типа ZeroMQ или RabbitMQ. Но не исключено, чот сделаю свой велосипед на общей памяти вместо TCP/IP.
Ну с в Net Core вроде обещали поддержку пайпов. Несложно переделать обмен по Tcp/ip. А чем тебе мой варианет не нравится?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>> А какая огромная разница между Protobuf и Json?
AVK>Производительность.
JSON применяется только для круных объектов, чтобы заполнять их на клиенте
Dictionary<int, string> ClientDict = new Dictionary<int, string>()
{
[1] = "Один",
[2] = "Второй2",
[3] = "Один3"
};
var @Dictionary2 = wrap.GetType("System.Collections.Generic.Dictionary`2", "System.Collections");
var @DictionaryIntString = wrap.GetGenericType(@Dictionary2, "System.Int32", "System.String");
// Скопируем словарь на сервер
// Закомментированы различные варианты
// var dict = connector.CoryTo(@DictionaryIntString, ClientDict);
// var dict = connector.CoryTo("System.Collections.Generic.Dictionary`2[System.Int32, System.String]", ClientDict);
// Скопируем словарь на серверvar dict = connector.CoryTo(ClientDict);
Для всех остальных обычная бинарная сериализация
stream.Write((byte)type);
// В зависимости от типа сериализуем объектswitch (type)
{
case EnumVar.VTYPE_I2: stream.Write((Int16)Объект); break;
case EnumVar.VTYPE_I4: stream.Write((Int32)Объект); break;
case EnumVar.VTYPE_R4: stream.Write((float)Объект); break;
case EnumVar.VTYPE_R8: stream.Write((double)Объект); break;
case EnumVar.VTYPE_Decimal: stream.Write((decimal)Объект); break;
case EnumVar.VTYPE_BOOL: stream.Write((bool)Объект); break;
case EnumVar.VTYPE_I1: stream.Write((sbyte)Объект); break;
case EnumVar.VTYPE_UI1: stream.Write((byte)Объект); break;
case EnumVar.VTYPE_UI2: stream.Write((UInt16)Объект); break;
case EnumVar.VTYPE_UI4: stream.Write((UInt32)Объект); break;
case EnumVar.VTYPE_I8: stream.Write((Int64)Объект); break;
case EnumVar.VTYPE_UI8: stream.Write((UInt64)Объект); break;
case EnumVar.VTYPE_CHAR: stream.Write((char)Объект); break;
case EnumVar.VTYPE_PWSTR: stream.Write((string)Объект); break;
case EnumVar.VTYPE_BLOB: stream.Write((byte[])Объект); break;
case EnumVar.VTYPE_DATE: WriteDateTime((DateTime)Объект, stream); break;
case EnumVar.VTYPE_GUID: stream.Write(((Guid)Объект).ToByteArray()); break;
case EnumVar.VTYPE_AutoWrap:
stream.Write(((AutoWrapClient)Объект).Target);
break;
}
return true;
S>>Для JSON есть прекрасная библиотека
AVK>Нашел новую игрушку? Увы, но для остальных это не аргумент.
JSON сериализация нужна для крупных объектов, что бы не заполнять их на сервере.
Если нужна скорость, то вручную сериализуй и десериализуй на сервере. Никто же не запрещает.
Я пока решил для объетов кроме вышеупомянутых не делать автоматическую сериализацию.
S>>Граблей с маршалингом нет, затраты на рефлексию
AVK>Затраты на рефлексию, по результатам реальных замеров, это 90% всей работы при передаче по ip. При передаче по более быстрым каналам, особенно по CrossAppDomainChannel цифра вообще близка к 100%.
Кстати не нашел пайпов для .Net Core. Может плохо искал?
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
AVK>>Производительность. S> При межпроцессном взаимодействии разница ничтожна.
Как раз при межпроцессном разница огромна, потому что каналы очень быстрые и с минимальной латентностью.
S> Угу. При внутрипроссном взаимодействии 500 000 вызовов в секунду
А латентность?
S>А по TCP всего 2000 вызовов в секунду.
Ты просто не умеешь его готовить.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Производительность. S>> При межпроцессном взаимодействии разница ничтожна.
AVK>Как раз при межпроцессном разница огромна, потому что каналы очень быстрые и с минимальной латентностью.
S>> Угу. При внутрипроссном взаимодействии 500 000 вызовов в секунду
AVK>А латентность?
S>>А по TCP всего 2000 вызовов в секунду.
AVK>Ты просто не умеешь его готовить.
Так вот я и спрашиваю как? Никто не отвечает
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>Ghb добавлении S>>using System?.IO?.Pipes S>> ругается на Pipes
AVK>
AVK>Assembly
AVK>System.IO.Pipes.dll
Нашел в \.nuget\packages\System.IO.Pipes\4.3.0\ref\netstandard1.3\
Но студия не хочет этот пакет использовать почему то.
Ладно добью библиотеку если это хоть кому то нужно будет сделаю и для пайпов. Там переделать всего 2 метода для эвентов и асинхронных методов.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>Ну опять же тебе нужно писать сервер.
AVK>Не знаю что ты там понимаешь под сервером, но tcp сервер пишется на дотнете в одно выражение.
Ну не в одно. Но обработку запросов кто писать будет?
Здесь берешь любой класс из любой сборки и работаешь с ним как с родным. Сейчас еще бинарные операции добавлю.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
S>>Ну опять же тебе нужно писать сервер.
AVK>Не знаю что ты там понимаешь под сервером, но tcp сервер пишется на дотнете в одно выражение.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Ты просто не умеешь его готовить. S>> Так вот я и спрашиваю как?
AVK>Что как?
S>> Никто не отвечает
AVK>Потому что ты вопросы задавать не умеешь.
Ну у меня сейчас каждый раз инициализируется соединение и разрыв после ответа.
Завтра посмотрю на постоянном соединении
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Не знаю что ты там понимаешь под сервером, но tcp сервер пишется на дотнете в одно выражение. S>>Ну не в одно.
AVK>Именно что в одно.
S>> Но обработку запросов кто писать будет?
AVK>Лямбды пока еще не отменили.
А лямбды кто писать будет?
По твоему и HTTP сервер тоже можно не писать.
Вот как сейчас выглядит обработка
static void SetResult(MemoryStream ms, NetworkStream ns)
{
ms.Position = 0;
ns.Write(BitConverter.GetBytes((Int32)ms.Length), 0, 4);
ms.CopyTo(ns);
ns.Flush();
}
private void RunMethod(NetworkStream ns, MemoryStream ms, IPAddress adress)
{
using (BinaryReader br = new BinaryReader(ms))
{
var msRes = new MemoryStream();
using(BinaryWriter bw= new BinaryWriter(msRes))
{
var cm = (CallMethod)br.ReadByte();
switch (cm)
{
case CallMethod.CallFunc: CallAsFunc(br, bw); break;
case CallMethod.GetMember: GetPropVal(br, bw); break;
case CallMethod.SetMember: SetPropVal(br, bw); break;
case CallMethod.CallFuncAsync: CallAsyncFunc(br, bw, adress); break;
case CallMethod.CallDelegate: CallAsDelegate(br, bw); break;
case CallMethod.CallGenericFunc: CallAsGenericFunc(br, bw); break;
case CallMethod.GetWrapperForObjectWithEvents: GetWrapperForObjectWithEvents(br, bw, adress); break;
case CallMethod.GetIndex: GetIndex(br, bw); break;
case CallMethod.SetIndex: SetIndex(br, bw); break;
case CallMethod.IteratorNext: IteratorNext(br, bw); break;
case CallMethod.DeleteObjects: DeleteObjects(br, bw); break;
}
bw.Flush();
SetResult(msRes, ns);
}
}
}
private void ExecuteMethod(TcpClient client)
{
var adress=((IPEndPoint)client.Client.RemoteEndPoint).Address;
// client.Client.NoDelay = true;using (NetworkStream ns = client.GetStream())
{
// Получим данные с клиента и на основании этих данных
//Создадим ДанныеДляКлиета1С котрый кроме данных содержит
//TcpClient для отправки ответаusing (var br = new BinaryReader(ns))
{
var streamSize = br.ReadInt32();
var res = br.ReadBytes(streamSize);
var ms = new MemoryStream(res);
ms.Position = 0;
RunMethod(ns, ms, adress);
}
}
}
static bool GetAW(BinaryReader br, BinaryWriter bw, out NetObjectToNative.AutoWrap AW )
{
var Target = br.ReadInt32();
AW = NetObjectToNative.AutoWrap.ObjectsList.GetValue(Target);
if (AW == null)
{
SetError("Не найдена ссылка на объект", bw);
return false;
}
return true;
}
public static bool CallAsFuncAll(BinaryReader br, BinaryWriter bw, out object result, bool WriteResult)
{
result = null;
NetObjectToNative.AutoWrap AW;
if (!GetAW(br, bw, out AW))
return false;
string MethodName = br.ReadString();
var args = GetArrayParams(br);
string Error;
List<int> ChageParams = new List<int>();
var res = AW.TryInvokeMember(MethodName, args, out result, ChageParams, out Error);
if (!res)
{
SetError(Error, bw);
return false;
}
if (WriteResult)
{
bw.Write(true);
WorkWhithVariant.WriteObject(NetObjectToNative.AutoWrap.WrapObject(result), bw);
WriteChandeParams(bw, args, ChageParams);
}
return true;
}
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
AVK>>Лямбды пока еще не отменили. S> А лямбды кто писать будет?
Лямбды могут быть частью одного выражения.
S>По твоему и HTTP сервер тоже можно не писать.
По моему простенький HTTP сервер для RPC по отношению к остальным задачам не стоит выеденного яйца. Если что — я в свое время исходники HttpChannel почти наизусть знал.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Лямбды пока еще не отменили. S>> А лямбды кто писать будет?
AVK>Лямбды могут быть частью одного выражения.
То есть с клиента передаешь сериализованные лямбды на сервер, компилируешь и выполняешь на сервере? S>>По твоему и HTTP сервер тоже можно не писать.
AVK>По моему простенький HTTP сервер для RPC по отношению к остальным задачам не стоит выеденного яйца. Если что — я в свое время исходники HttpChannel почти наизусть знал.
Прошу прощения неправильно выразился. В данном случае и мел ввиду сервис. То есть Web Api Controllers.
В моем случае можно специально не писать даже сборки. Ибо можно использовать динамическую компиляцию. Она кстати у меня используется для создания Proxy для подключения к событиям.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Лямбды пока еще не отменили. S>> А лямбды кто писать будет?
AVK>Лямбды могут быть частью одного выражения.
Кстати дал бы ссылочку на правильную работу с Tcp.
Я так понимаю нужен кэш на постоянное соединение, так как есть вызовы из Эвеннтов а и задачи могут применяться.
Завтра сравню скорость с постоянным соединением и подключением . Но для аналога AppDomain нужны пайпы.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Serginio1, Вы писали:
AVK>>>Ты просто не умеешь его готовить. S>> Так вот я и спрашиваю как?
AVK>Что как?
S>> Никто не отвечает
AVK>Потому что ты вопросы задавать не умеешь.
Здравствуйте, vorona, Вы писали:
V>Здравствуйте, Serginio1, Вы писали:
S>>Здравствуйте, Serginio1, Вы писали:
S>>Хочу написать статью. И прошу совета какой пример показать в вау эффектом.
V>Нужно придумать реальную задачу которую удобно решить с помощью твоего велосипеда.
На самом деле это замена AppDomain. Смысл, что то сделать и выгрузить.
Второе это управление приложением из другого приложения например через статические методы и свойства.
и солнце б утром не вставало, когда бы не было меня
Надеюсь на помощь в примеров с вау эффектом для удаленного вызова.
Например можно выводить сообщение в консоли сервера
string typeStr = typeof(Console).AssemblyQualifiedName;
var _Console = wrap.GetType(typeStr);// Получим тип на сервере по имени
// "Hello from Client" будет выведено в консоле сервера
_Console.WriteLine("Hello from Client");
и солнце б утром не вставало, когда бы не было меня
Re: .Net Core, AppDomain, WCF, RPC маршалинг по Tcp/Ip свой вело
В ней подробно рассказывается как создавать удаленные объекты и вызывать их методы.
Само решение очень близко с COM out process взаимодействием на IDispatch.
Помню с удовольствием разбирался с внутренностями TSocketConnection.
Но, в отличие от Idispatch, используется перегрузка методов и операторов, вызов Generic методов с выводом типов или с заданием Generic аргументов.
Поддержка методов расширений для классов, находящихся в одной сборке и для Linq методов.
Также поддержка асинхронных методов и подписка на события, ref и out параметры, доступ по индексу [], поддержка итераторов в foreach.
В отличии от Web Api, не нужно писать специально серверный код Controller, Hub ы.
Это близко к AppDomain c Remouting но, в отличие от Remoting, каждый класс является аналогом MarshalByRefObject. То есть, мы можем создать любой объект на стороне сервера и вернуть ссылку на него (некоторые языки из чисел поддерживают только double).
При вызове методов, напрямую сериализуются параметры только следующих типов: числа, строки, дата, Guid и byte[]. Для остальных типов нужно их создать на стороне сервера, а в параметрах методов уже передаются ссылки на них.
и солнце б утром не вставало, когда бы не было меня