//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; } }
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); }
/// <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); }
//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); }
//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); }
//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; } }
//通过客户端的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()); }
//通过客户端的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()); }
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; } } }
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(); } }
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}对服务端传输关闭。"); }
//通过客户端的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()); }