コード例 #1
0
        //3端互相传输数据
        async Task TcpTransferAsync(Stream consumerStream, Stream providerStream,
                                    NSPApp nspApp,
                                    CancellationToken ct)
        {
            try
            {
                Server.Logger.Debug($"New client ({nspApp.ClientId}-{nspApp.AppId}) connected");

                //CancellationTokenSource transfering = new CancellationTokenSource();

                //var providerStream = providerClient.GetStream();//.ProcessSSL("test");
                //var consumerStream = consumerClient.GetStream();
                Task taskC2PLooping = ToStaticTransfer(ct, consumerStream, providerStream, nspApp);
                Task taskP2CLooping = StreamTransfer(ct, providerStream, consumerStream, nspApp);

                //任何一端传输中断或者故障,则关闭所有连接
                var comletedTask = await Task.WhenAny(taskC2PLooping, taskP2CLooping);

                //comletedTask.
                Logger.Debug($"Transferring ({nspApp.ClientId}-{nspApp.AppId}) STOPPED");
            }
            catch (Exception e)
            {
                Logger.Debug(e);
                throw;
            }
        }
コード例 #2
0
        public async Task <TcpClient> GetClientForUdp(int consumerPort, string host = null)
        {
            NSPApp nspApp = null;

            nspApp = ServerContext.UDPPortAppMap[consumerPort].ActivateApp;

            TcpClient client = nspApp.TcpClientBlocks.Peek();

            if (client == null)
            {
                throw new TimeoutException($"UDP获取{consumerPort}失败");
            }
            return(client);
        }
コード例 #3
0
        /// <summary>
        /// 注册app并且返回appid(非线程安全)
        /// </summary>
        /// <returns></returns>
        public int RegisterNewApp()
        {
            //按顺序分配最大int
            int preAppId = 1;

            if (AppMap.Count > 0)
            {
                preAppId = AppMap.Last().Key + 1;
            }

            NSPApp app = this.AppMap[preAppId] = new NSPApp()
            {
                AppId    = preAppId,
                ClientId = ClientID
            };

            return(app.AppId);
        }
コード例 #4
0
        //public async Task<TcpClient> GetHTTPClient(int consumerPort)
        //{
        //    var clientId = ServerContext.PortAppMap[consumerPort].ClientId;
        //    var appId = ServerContext.PortAppMap[consumerPort].AppId;

        //    //TODO ***需要处理服务端长时间不来请求的情况(无法建立隧道)
        //    TcpClient client = await ServerContext.Clients[clientId].AppMap[appId].PopClientAsync();
        //    if (client == null) return null;
        //    ServerContext.PortAppMap[consumerPort].ReverseClients.Add(client);
        //    return client;
        //}

        public async Task <TcpClient> GetClient(int consumerPort, string host = null)
        {
            NSPApp nspApp = null;

            if (host == null || string.IsNullOrEmpty(host.Trim())) //host为空则随便匹配一个
            {
                nspApp = ServerContext.PortAppMap[consumerPort].ActivateApp;
            }
            else
            {
                if (!ServerContext.PortAppMap[consumerPort].TryGetValue(host, out nspApp))
                {
                    //throw new KeyNotFoundException($"无法找到{consumerPort}的host:{host}");
                    Server.Logger.Debug($"无法找到{consumerPort}的host:{host}");
                    nspApp = ServerContext.PortAppMap[consumerPort].ActivateApp;
                }
            }
            if (nspApp == null)
            {
                throw new KeyNotFoundException($"无法找到{consumerPort}下的任何一个客户端app");
            }
            //if (NSPApp.AppProtocol == Protocol.HTTP)
            //{
            //    //NSPApp.

            //}

            //var clientId = NSPApp.ClientId;
            //var appId = NSPApp.AppId;

            //TODO ***需要处理服务端长时间不来请求的情况(无法建立隧道)
            //TODO 2这里的弹出比较麻烦了
            TcpClient client = await nspApp.PopClientAsync();

            if (client == null)
            {
                throw new TimeoutException($"弹出{consumerPort}超时");
            }

            //TODO 2 反向链接还写在这里??
            //ServerContext.PortAppMap[consumerPort].ActivateApp.ReverseClients.Add(client);
            nspApp.ReverseClients.Add(client);
            return(client);
        }
コード例 #5
0
        //public async Task<TcpClient> GetHTTPClient(int consumerPort)
        //{
        //    var clientId = ServerContext.PortAppMap[consumerPort].ClientId;
        //    var appId = ServerContext.PortAppMap[consumerPort].AppId;

        //    //TODO ***需要处理服务端长时间不来请求的情况(无法建立隧道)
        //    TcpClient client = await ServerContext.Clients[clientId].AppMap[appId].PopClientAsync();
        //    if (client == null) return null;
        //    ServerContext.PortAppMap[consumerPort].ReverseClients.Add(client);
        //    return client;
        //}

        public async Task <TcpClient> GetClient(int consumerPort, string host = null)
        {
            NSPApp NSPApp = null;

            if (host == null)
            {
                NSPApp = ServerContext.PortAppMap[consumerPort].ActivateApp;
            }
            else
            {
                if (!ServerContext.PortAppMap[consumerPort].TryGetValue(host, out NSPApp))
                {
                    throw new KeyNotFoundException($"无法找到{consumerPort}的host:{host}");
                }
            }

            //if (NSPApp.AppProtocol == Protocol.HTTP)
            //{
            //    //NSPApp.

            //}

            //var clientId = NSPApp.ClientId;
            //var appId = NSPApp.AppId;

            //TODO ***需要处理服务端长时间不来请求的情况(无法建立隧道)
            //TODO 2这里的弹出比较麻烦了
            TcpClient client = await NSPApp.PopClientAsync();

            if (client == null)
            {
                throw new TimeoutException($"弹出{consumerPort}超时");
            }

            //TODO 2 反向链接还写在这里??
            //ServerContext.PortAppMap[consumerPort].ActivateApp.ReverseClients.Add(client);
            NSPApp.ReverseClients.Add(client);
            return(client);
        }
コード例 #6
0
        //3端互相传输数据
        async Task OpenTcpTransmission(Stream consumerStream, Stream providerStream,
                                       NSPApp nspApp,
                                       CancellationToken ct)
        {
            try
            {
                Server.Logger.Debug($"New client ({nspApp.ClientId}-{nspApp.AppId}) connected");

                Task taskC2PLooping = ToStaticTransfer(ct, consumerStream, providerStream, nspApp);
                Task taskP2CLooping = StreamTransfer(ct, providerStream, consumerStream, nspApp);

                //任何一端传输中断或者故障,则关闭所有连接
                var comletedTask = await Task.WhenAny(taskC2PLooping, taskP2CLooping);

                Logger.Debug($"Transferring ({nspApp.ClientId}-{nspApp.AppId}) STOPPED");
            }
            catch (Exception e)
            {
                Logger.Debug(e);
                throw;
            }
        }
コード例 #7
0
        //通过客户端的id请求,分配好服务端端口和appid交给客户端
        //arrange ConfigId from top 4 bytes which received from client.
        //response:
        //   2          1       1       1           1        ...N
        //  clientid    appid   port    appid2      port2
        //request:
        //   2          2
        //  clientid    count
        //  methodType  value = 0
        public byte[] ArrageConfigIds(byte[] appRequestBytes, byte[] consumerPortBytes)
        {
            // byte[] arrangedBytes = new byte[256];
            ClientModel clientModel = new ClientModel();
            int         clientId    = (appRequestBytes[0] << 8) + appRequestBytes[1];
            int         appCount    = (int)appRequestBytes[2];

            if (clientId == 0)
            {
                lock (_lockObject)
                {
                    byte[] tempClientIdBytes = new byte[2];
                    //分配clientid
                    for (int i = 0; i < 10000; i++)
                    {
                        _rand.NextBytes(tempClientIdBytes);
                        int tempClientId = (tempClientIdBytes[0] << 8) + tempClientIdBytes[1];
                        if (!Clients.ContainsKey(tempClientId))
                        {
                            clientModel.ClientId = tempClientId;
                            clientId             = tempClientId;

                            break;
                        }
                    }
                }
            }
            else
            {
                clientModel.ClientId = clientId;
            }

            //注册客户端
            Clients.RegisterNewClient(clientModel.ClientId);
            lock (_lockObject2)
            {
                //注册app
                clientModel.AppList = new List <App>(appCount);
                for (int i = 0; i < appCount; i++)
                {
                    int startPort = StringUtil.DoubleBytesToInt(consumerPortBytes[2 * i], consumerPortBytes[2 * i + 1]);

                    int arrangedAppid = Clients[clientId].RegisterNewApp();
                    //查找port的起始端口如果未指定,则设置为20000
                    if (startPort == 0)
                    {
                        startPort = 20000;
                    }
                    int    port = NetworkUtil.FindOneAvailableTCPPort(startPort);
                    NSPApp app  = Clients[clientId].AppMap[arrangedAppid];
                    app.ClientId       = clientId;
                    app.AppId          = arrangedAppid;
                    app.ConsumePort    = port;
                    app.Tunnels        = new List <TcpTunnel>();
                    app.ReverseClients = new List <TcpClient>();
                    PortAppMap[port]   = app;

                    clientModel.AppList.Add(new App
                    {
                        AppId = arrangedAppid,
                        Port  = port
                    });

                    Logger.Info(port);
                    //配置时触发
                    AppTcpClientMapConfigConnected(this, new AppChangedEventArgs()
                    {
                        App = app
                    });
                }
                Logger.Debug(" <=端口已分配。");
            }
            return(clientModel.ToBytes());
        }
コード例 #8
0
        //通过客户端的id请求,分配好服务端端口和appid交给客户端
        //arrange ConfigId from top 4 bytes which received from client.
        //response:
        //   2          1       1       1           1        ...N
        //  clientid    appid   port    appid2      port2
        //request:
        //   2          2
        //  clientid    count
        //  methodType  value = 0
        public byte[] ArrangeConfigIds(byte[] appRequestBytes, byte[] consumerPortBytes, int highPriorityClientId)
        {
            // byte[] arrangedBytes = new byte[256];
            ClientModel clientModel = new ClientModel();
            int         clientId;

            //apprequestbytes里本身有clientId,但是如果传了highPriorityClientId,那就用这个clientId
            if (highPriorityClientId != 0)
            {
                clientId = highPriorityClientId;
            }
            else
            {
                clientId = StringUtil.DoubleBytesToInt(appRequestBytes[0], appRequestBytes[1]);
            }

            //2.分配clientid //TODO 这一段可能不会再用到了
            int appCount = (int)appRequestBytes[2];

            if (clientId == 0)
            {
                lock (_lockObject)
                {
                    byte[] tempClientIdBytes = new byte[2];
                    //分配clientid
                    for (int i = 0; i < 10000; i++)
                    {
                        _rand.NextBytes(tempClientIdBytes);
                        int tempClientId = (tempClientIdBytes[0] << 8) + tempClientIdBytes[1];
                        if (!ServerContext.Clients.ContainsKey(tempClientId))
                        {
                            clientModel.ClientId = tempClientId;
                            clientId             = tempClientId;

                            break;
                        }
                    }
                }
            }
            else
            {
                clientModel.ClientId = clientId;
            }

            //注册客户端
            ServerContext.Clients.RegisterNewClient(clientModel.ClientId);
            int oneEndpointLength = 2 + 1 + 1024;

            lock (_lockObject2)
            {
                //注册app
                clientModel.AppList = new List <App>(appCount);
                for (int i = 0; i < appCount; i++)
                {
                    int      offset        = oneEndpointLength * i;
                    int      startPort     = StringUtil.DoubleBytesToInt(consumerPortBytes[offset], consumerPortBytes[offset + 1]);
                    int      arrangedAppid = ServerContext.Clients[clientId].RegisterNewApp();
                    Protocol protocol      = (Protocol)consumerPortBytes[offset + 2];
                    string   host          = Encoding.ASCII.GetString(consumerPortBytes, offset + 3, 1024).TrimEnd('\0');
                    //查找port的起始端口如果未指定,则设置为20000
                    if (startPort == 0)
                    {
                        startPort = Global.StartArrangedPort;
                    }
                    int port = 0;
                    //如果端口是指定的并且是绑定的,不加任何检测
                    bool hasListened = false;
                    if (IsBoundedByUser(clientId, startPort))
                    {
                        port = startPort;
                    }
                    else
                    {
                        int relocatedPort = NetworkUtil.FindOneAvailableTCPPort(startPort);
                        if (protocol == Protocol.TCP)
                        {
                            port = relocatedPort; //TODO 2 如果是共享端口协议,如果找不到端口则不进行侦听
                        }
                        else if (protocol == Protocol.HTTP)
                        {
                            //兼容http侦听端口公用
                            if (port != relocatedPort)
                            {
                                //http协议下如果portappmap已经有值,说明已经发起过侦听,接下来不必再侦听
                                if (ServerContext.PortAppMap.ContainsKey(startPort))
                                {
                                    port        = startPort;
                                    hasListened = true;
                                }
                                else
                                {
                                    port = relocatedPort;
                                }
                            }
                        }
                    }
                    NSPApp app = ServerContext.Clients[clientId].AppMap[arrangedAppid];
                    app.ClientId       = clientId;
                    app.AppId          = arrangedAppid;
                    app.ConsumePort    = port;
                    app.AppProtocol    = protocol;
                    app.Host           = host;
                    app.Tunnels        = new List <TcpTunnel>();
                    app.ReverseClients = new List <TcpClient>();
                    //app.Host = host;
                    //TODO 设置app的host和protocoltype
                    if (!ServerContext.PortAppMap.ContainsKey(port))
                    {
                        ServerContext.PortAppMap[port] = new NSPAppGroup();
                    }

                    if (protocol == Protocol.HTTP)
                    {
                        ServerContext.PortAppMap[port].Add(host, app);
                    }

                    ServerContext.PortAppMap[port].ActivateApp = app;
                    //ServerContext.PortAppMap[port] = nspAppGroup;

                    clientModel.AppList.Add(new App
                    {
                        AppId = arrangedAppid,
                        Port  = port
                    });

                    Logger.Info(port);
                    //配置时触发
                    if (!hasListened)
                    {
                        AppTcpClientMapConfigConnected(this, new AppChangedEventArgs()
                        {
                            App = app
                        });                                                                           //触发listener侦听
                    }
                }
                Logger.Debug(" <=端口已分配。");
            }
            return(clientModel.ToBytes());
        }
コード例 #9
0
 private async Task ToStaticTransfer(CancellationToken ct, Stream fromStream, Stream toStream, NSPApp nspApp)
 {
     using (fromStream)
     {
         byte[] buffer = new byte[Global.ServerTunnelBufferSize];
         try
         {
             int bytesRead;
             while ((bytesRead =
                         await fromStream.ReadAsync(buffer, 0, buffer.Length, ct).ConfigureAwait(false)) != 0)
             {
                 if (nspApp.IsCompress)
                 {
                     var compressInSnappy = StringUtil.CompressInSnappy(buffer, 0, bytesRead);
                     var compressedBuffer = compressInSnappy.ContentBytes;
                     bytesRead = compressInSnappy.Length;
                     await toStream.WriteAsync(compressedBuffer, 0, bytesRead, ct).ConfigureAwait(false);
                 }
                 else
                 {
                     await toStream.WriteAsync(buffer, 0, bytesRead, ct).ConfigureAwait(false);
                 }
                 ServerContext.TotalReceivedBytes += bytesRead; //下行
             }
         }
         catch (Exception ioe)
         {
             if (ioe is IOException)
             {
                 return;
             }                                   //Suppress this exception.
             throw;
         }
     }
 }
コード例 #10
0
        private async Task ProcessConsumeTcpRequestAsync(int consumerPort, TcpClient consumerClient, CancellationToken ct)
        {
            TcpTunnel tunnel = new TcpTunnel {
                ConsumerClient = consumerClient
            };
            var       nspAppGroup    = ServerContext.PortAppMap[consumerPort];
            NSPApp    nspApp         = null;
            TcpClient s2pClient      = null;
            Stream    consumerStream = consumerClient.GetStream();
            Stream    providerStream = null;

            byte[] restBytes = null;

            try
            {
                if (nspAppGroup.ProtocolInGroup == Protocol.HTTP /*|| nspAppGroup.ProtocolInGroup == Protocol.HTTPS*/)
                {//不论是http协议还是https协议,有证书就加密
                    if (ServerContext.PortCertMap.TryGetValue(consumerPort.ToString(), out X509Certificate cert2))
                    {
                        consumerStream = consumerStream.ProcessSSL(cert2);
                    }
                    var tp = await ReadHostName(consumerStream);

                    if (tp == null)
                    {
                        Server.Logger.Debug("未在请求中找到主机名"); return;
                    }

                    string host = tp.Item1;
                    restBytes = Encoding.UTF8.GetBytes(tp.Item2); //预发送bytes,因为这部分用来抓host消费掉了
                    //restBytesLength = tp.Item3;
                    s2pClient = await ConnectionManager.GetClientForTcp(consumerPort, host);

                    if (nspAppGroup.ContainsKey(host))
                    {
                        nspAppGroup[host].Tunnels.Add(tunnel); //bug修改:建立隧道
                    }
                    else
                    {
                        Server.Logger.Debug($"不存在host为“{host}”的主机名,但访问端依然以此主机名访问。");
                    }

                    nspApp = nspAppGroup[host];
                }
                else if (nspAppGroup.ProtocolInGroup == Protocol.TCP) //TCP
                {
                    s2pClient = await ConnectionManager.GetClientForTcp(consumerPort);

                    nspAppGroup.ActivateApp.Tunnels.Add(tunnel);//bug修改:建立隧道
                    nspApp = nspAppGroup.ActivateApp;
                }
            }
            catch (TimeoutException ex)
            {
                Logger.Debug($"端口{consumerPort}获取反弹连接超时,关闭传输。=>" + ex.Message);
                //获取clientid
                //关闭本次连接
                ServerContext.CloseAllSourceByClient(ServerContext.PortAppMap[consumerPort].ActivateApp.ClientId);
                return;
            }
            catch (KeyNotFoundException ex)
            {
                Server.Logger.Debug("未绑定此host:=>" + ex.Message);
                consumerClient.Close();
                return;
            }

            ServerContext.ConnectCount += 1;

            //TODO 如果NSPApp中是http,则需要进一步分离,通过GetHTTPClient来分出对应的client以建立隧道
            //II.弹出先前已经准备好的socket
            tunnel.ClientServerClient = s2pClient;
            CancellationTokenSource transfering = new CancellationTokenSource();

            //✳关键过程✳
            //III.发送一个字节过去促使客户端建立转发隧道,至此隧道已打通
            //客户端接收到此消息后,会另外分配一个备用连接

            //TODO 4 增加一个udp转发的选项
            providerStream = s2pClient.GetStream();
            //TODO 5 这里会出错导致无法和客户端通信
            try
            {
                await providerStream.WriteAndFlushAsync(new byte[] { (byte)ControlMethod.TCPTransfer }, 0, 1);//双端标记S0001
            }
            catch
            {
                Logger.Debug($"client:{nspApp.ClientId} app:{nspApp.AppId}写入失败,尝试切断该客户端");
                ServerContext.CloseAllSourceByClient(nspApp.ClientId);
                return;
            }

            //预发送bytes,因为这部分用来抓host消费掉了,所以直接转发
            if (restBytes != null)
            {
                await providerStream.WriteAsync(restBytes, 0, restBytes.Length, transfering.Token);
            }

            //TODO 4 TCP则打通隧道进行转发,UDP直接转发
            // if tcp
            try
            {
                await OpenTcpTransmission(consumerStream, providerStream, nspApp, transfering.Token);
            }
            finally
            {
                consumerClient.Close();
                s2pClient.Close();
                transfering.Cancel();
            }
        }
コード例 #11
0
        private async Task StreamTransfer(CancellationToken ct, Stream fromStream, Stream toStream, NSPApp nspApp)
        {
            using (fromStream)
            {
                byte[] buffer = new byte[81920];
                try
                {
                    int bytesRead;
                    while ((bytesRead =
                                await fromStream.ReadAsync(buffer, 0, buffer.Length, ct).ConfigureAwait(false)) != 0)
                    {
                        if (nspApp.IsCompressed)
                        {
                            buffer    = StringUtil.DecompressInSnappy(buffer, 0, bytesRead);
                            bytesRead = buffer.Length;
                        }

                        await toStream.WriteAsync(buffer, 0, bytesRead, ct).ConfigureAwait(false);

                        ServerContext.TotalSentBytes += bytesRead; //上行
                    }
                }
                catch (Exception ioe)
                {
                    if (ioe is IOException)
                    {
                        return;
                    }                                   //Suppress this exception.
                    throw;
                    //Server.Logger.Info(ioe.Message);
                }
            }
            //Server.Logger.Debug($"{clientApp}对服务端传输关闭。");
        }
コード例 #12
0
        //通过客户端的id请求,分配好服务端端口和appid交给客户端
        //arrange ConfigId from top 4 bytes which received from client.
        //response:
        //   2          1       1       1           1        ...N
        //  clientid    appid   port    appid2      port2
        //request:
        //   2          2
        //  clientid    count
        //  methodType  value = 0
        public byte[] ArrangeConfigIds(byte[] appRequestBytes, byte[] consumerPortBytes, int highPriorityClientId)
        {
            // byte[] arrangedBytes = new byte[256];
            ClientModel clientModel = new ClientModel();
            int         clientId;

            //apprequestbytes里本身有clientId,但是如果传了highPriorityClientId,那就用这个clientId
            if (highPriorityClientId != 0)
            {
                clientId = highPriorityClientId;
            }
            else
            {
                clientId = StringUtil.DoubleBytesToInt(appRequestBytes[0], appRequestBytes[1]);
            }


            //2.分配clientid //TODO 这一段可能不会再用到了
            int appCount = (int)appRequestBytes[2];

            if (clientId == 0)
            {
                lock (_lockObject)
                {
                    byte[] tempClientIdBytes = new byte[2];
                    //分配clientid
                    for (int i = 0; i < 10000; i++)
                    {
                        _rand.NextBytes(tempClientIdBytes);
                        int tempClientId = (tempClientIdBytes[0] << 8) + tempClientIdBytes[1];
                        if (!ServerContext.Clients.ContainsKey(tempClientId))
                        {
                            clientModel.ClientId = tempClientId;
                            clientId             = tempClientId;

                            break;
                        }
                    }
                }
            }
            else
            {
                clientModel.ClientId = clientId;
            }

            //注册客户端
            ServerContext.Clients.RegisterNewClient(clientModel.ClientId);
            lock (_lockObject2)
            {
                //注册app
                clientModel.AppList = new List <App>(appCount);
                for (int i = 0; i < appCount; i++)
                {
                    int startPort     = StringUtil.DoubleBytesToInt(consumerPortBytes[2 * i], consumerPortBytes[2 * i + 1]);
                    int arrangedAppid = ServerContext.Clients[clientId].RegisterNewApp();
                    //查找port的起始端口如果未指定,则设置为20000
                    if (startPort == 0)
                    {
                        startPort = 20000;
                    }
                    int port = 0;
                    //TODO QQQ 如果端口是指定的并且是绑定的,则直接使用该端口即可
                    if (IsBoundedByUser(clientId, startPort))
                    {
                        port = startPort;
                    }
                    else
                    {
                        port = NetworkUtil.FindOneAvailableTCPPort(startPort);
                    }
                    NSPApp app = ServerContext.Clients[clientId].AppMap[arrangedAppid];
                    app.ClientId                   = clientId;
                    app.AppId                      = arrangedAppid;
                    app.ConsumePort                = port;
                    app.Tunnels                    = new List <TcpTunnel>();
                    app.ReverseClients             = new List <TcpClient>();
                    ServerContext.PortAppMap[port] = app;

                    clientModel.AppList.Add(new App
                    {
                        AppId = arrangedAppid,
                        Port  = port
                    });

                    Logger.Info(port);
                    //配置时触发
                    AppTcpClientMapConfigConnected(this, new AppChangedEventArgs()
                    {
                        App = app
                    });
                }
                Logger.Debug(" <=端口已分配。");
            }
            return(clientModel.ToBytes());
        }