Пример #1
0
        /// <summary>
        /// create TCP unix domain socket client and connect to server
        /// </summary>
        /// <param name="domainSocketPath">path to unix domain socket</param>
        /// <exception cref="SocketException">unix domain socket not supported or server does not listen</exception>
        /// <returns>TCP socket client.</returns>
        public static SocketTcpClient ConnectUds(string domainSocketPath)
        {
            var client = new SocketTcpClient(AddressFamily.Unix, ProtocolType.IP);

            client.socket.Connect(new UnixDomainSocketEndPoint(domainSocketPath));
            return(client);
        }
Пример #2
0
        public TcpWorker(IServiceProvider provider, MessagePipeInterprocessTcpOptions options, IAsyncPublisher <IInterprocessKey, IInterprocessValue> publisher)
        {
            this.provider = provider;
            this.cancellationTokenSource = new CancellationTokenSource();
            this.options   = options;
            this.publisher = publisher;

            this.server = new Lazy <SocketTcpServer>(() =>
            {
                return(SocketTcpServer.Listen(options.Host, options.Port));
            });

            this.client = new Lazy <SocketTcpClient>(() =>
            {
                return(SocketTcpClient.Connect(options.Host, options.Port));
            });

#if !UNITY_2018_3_OR_NEWER
            this.channel = Channel.CreateUnbounded <byte[]>(new UnboundedChannelOptions()
            {
                SingleReader = true,
                SingleWriter = false,
                AllowSynchronousContinuations = true
            });
#else
            this.channel = Channel.CreateSingleConsumerUnbounded <byte[]>();
#endif

            if (options.HostAsServer != null && options.HostAsServer.Value)
            {
                StartReceiver();
            }
        }
Пример #3
0
        public static SocketTcpClient Connect(string host, int port)
        {
            var ip     = new IPEndPoint(IPAddress.Parse(host), port);
            var client = new SocketTcpClient(ip.AddressFamily, ProtocolType.Tcp);

            client.socket.Connect(ip);
            return(client);
        }
Пример #4
0
        static async ValueTask ReadFullyAsync(byte[] buffer, SocketTcpClient client, int index, int remain, CancellationToken token)
        {
            while (remain > 0)
            {
                var len = await client.ReceiveAsync(buffer, index, remain, token).ConfigureAwait(false);

                index  += len;
                remain -= len;
            }
        }
Пример #5
0
        // Receive from tcp socket and push value to subscribers.
        async void RunReceiveLoop(SocketTcpClient client)
        {
            var token  = cancellationTokenSource.Token;
            var buffer = new byte[65536];
            ReadOnlyMemory <byte> readBuffer = Array.Empty <byte>();

            while (!token.IsCancellationRequested)
            {
                ReadOnlyMemory <byte> value = Array.Empty <byte>();
                try
                {
                    if (readBuffer.Length == 0)
                    {
                        var readLen = await client.ReceiveAsync(buffer, 0, buffer.Length, token).ConfigureAwait(false);

                        if (readLen == 0)
                        {
                            return;               // end of stream(disconnect)
                        }
                        readBuffer = buffer.AsMemory(0, readLen);
                    }
                    else if (readBuffer.Length < 4) // rare case
                    {
                        var readLen = await client.ReceiveAsync(buffer, 0, buffer.Length, token).ConfigureAwait(false);

                        if (readLen == 0)
                        {
                            return;
                        }
                        var newBuffer = new byte[readBuffer.Length + readLen];
                        readBuffer.CopyTo(newBuffer);
                        buffer.AsSpan(readLen).CopyTo(newBuffer.AsSpan(readBuffer.Length));
                        readBuffer = newBuffer;
                    }

                    var messageLen = MessageBuilder.FetchMessageLength(readBuffer.Span);
                    if (readBuffer.Length == (messageLen + 4))        // just size
                    {
                        value      = readBuffer.Slice(4, messageLen); // skip length header
                        readBuffer = Array.Empty <byte>();
                        goto PARSE_MESSAGE;
                    }
                    else if (readBuffer.Length > (messageLen + 4)) // over size
                    {
                        value      = readBuffer.Slice(4, messageLen);
                        readBuffer = readBuffer.Slice(messageLen + 4);
                        goto PARSE_MESSAGE;
                    }
                    else // needs to read more
                    {
                        var readLen = readBuffer.Length;
                        if (readLen < (messageLen + 4))
                        {
                            if (readBuffer.Length != buffer.Length)
                            {
                                var newBuffer = new byte[buffer.Length];
                                readBuffer.CopyTo(newBuffer);
                                buffer = newBuffer;
                            }

                            if (buffer.Length < messageLen + 4)
                            {
                                Array.Resize(ref buffer, messageLen + 4);
                            }
                        }
                        var remain = messageLen - (readLen - 4);
                        await ReadFullyAsync(buffer, client, readLen, remain, token).ConfigureAwait(false);

                        value      = buffer.AsMemory(4, messageLen);
                        readBuffer = Array.Empty <byte>();
                        goto PARSE_MESSAGE;
                    }
                }
                catch (Exception ex)
                {
                    if (ex is OperationCanceledException)
                    {
                        return;
                    }
                    if (token.IsCancellationRequested)
                    {
                        return;
                    }

                    // network error, terminate.
                    options.UnhandledErrorHandler("network error, receive loop will terminate." + Environment.NewLine, ex);
                    return;
                }
PARSE_MESSAGE:
                try
                {
                    var message = MessageBuilder.ReadPubSubMessage(value.ToArray()); // can avoid copy?
                    switch (message.MessageType)
                    {
                    case MessageType.PubSub:
                        publisher.Publish(message, message, CancellationToken.None);
                        break;

                    case MessageType.RemoteRequest:
                    {
                        // NOTE: should use without reflection(Expression.Compile)
                        var header = Deserialize <RequestHeader>(message.KeyMemory, options.MessagePackSerializerOptions);
                        var(mid, reqTypeName, resTypeName) = (header.MessageId, header.RequestType, header.ResponseType);
                        byte[] resultBytes;
                        try
                        {
                            var t                 = AsyncRequestHandlerRegistory.Get(reqTypeName, resTypeName);
                            var interfaceType     = t.GetInterfaces().First(x => x.IsGenericType && x.Name.StartsWith("IAsyncRequestHandler"));
                            var coreInterfaceType = t.GetInterfaces().First(x => x.IsGenericType && x.Name.StartsWith("IAsyncRequestHandlerCore"));
                            var service           = provider.GetRequiredService(interfaceType); // IAsyncRequestHandler<TRequest,TResponse>
                            var genericArgs       = interfaceType.GetGenericArguments();        // [TRequest, TResponse]
                            // Unity IL2CPP does not work(can not invoke nongenerics MessagePackSerializer)
                            var request      = MessagePackSerializer.Deserialize(genericArgs[0], message.ValueMemory, options.MessagePackSerializerOptions);
                            var responseTask = coreInterfaceType.GetMethod("InvokeAsync") !.Invoke(service, new[] { request, CancellationToken.None });
#if !UNITY_2018_3_OR_NEWER
                            var task = typeof(ValueTask <>).MakeGenericType(genericArgs[1]).GetMethod("AsTask") !.Invoke(responseTask, null);
#else
                            var asTask = typeof(UniTaskExtensions).GetMethods().First(x => x.IsGenericMethod && x.Name == "AsTask")
                                         .MakeGenericMethod(genericArgs[1]);
                            var task = asTask.Invoke(null, new[] { responseTask });
#endif
                            await((System.Threading.Tasks.Task)task !);         // Task<T> -> Task
                            var result = task.GetType().GetProperty("Result") !.GetValue(task);
                            resultBytes = MessageBuilder.BuildRemoteResponseMessage(mid, genericArgs[1], result !, options.MessagePackSerializerOptions);
                        }
                        catch (Exception ex)
                        {
                            // NOTE: ok to send stacktrace?
                            resultBytes = MessageBuilder.BuildRemoteResponseError(mid, ex.ToString(), options.MessagePackSerializerOptions);
                        }

                        await client.SendAsync(resultBytes).ConfigureAwait(false);
                    }
                    break;

                    case MessageType.RemoteResponse:
                    case MessageType.RemoteError:
                    {
                        var mid = Deserialize <int>(message.KeyMemory, options.MessagePackSerializerOptions);
                        if (responseCompletions.TryRemove(mid, out var tcs))
                        {
                            if (message.MessageType == MessageType.RemoteResponse)
                            {
                                tcs.TrySetResult(message);         // synchronous completion, use memory buffer immediately.
                            }
                            else
                            {
                                var errorMsg = MessagePackSerializer.Deserialize <string>(message.ValueMemory, options.MessagePackSerializerOptions);
                                tcs.TrySetException(new RemoteRequestException(errorMsg));
                            }
                        }
                    }
                    break;

                    default:
                        break;
                    }
                }
                catch (Exception ex)
                {
                    if (ex is OperationCanceledException)
                    {
                        continue;
                    }
                    options.UnhandledErrorHandler("", ex);
                }
            }
        }