static void Main(string[] args) { string filePath = "E:/test.zip"; FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read); DynamicListener listener = new DynamicListener(/*IPAddress.Any*/ IPAddress.Parse("192.168.1.73"), 54321); // netsh http add urlacl url=http://+:54322/ws user=everyone //WsListener listener = new WsListener("http://+:54322/ws/"); listener.Start(); //TCPRemoteClient client = new TCPRemoteClient(); //WsRemoteClient client = new WsRemoteClient(); ProtocolTree tree = new ProtocolTree(); LeafProtocolHandler <Data> leaf = new LeafProtocolHandler <Data>(); LeafProtocolHandler <Rec> rec = new LeafProtocolHandler <Rec>(); LeafProtocolHandler <Done> done = new LeafProtocolHandler <Done>(); tree.Register(leaf); tree.Register(rec); tree.Register(done); tree.EntryToLeaf(leaf); tree.EntryToLeaf(rec); tree.EntryToLeaf(done); ApplicationConnectionManager app = null; //TcpClient cl = null; //WebSocket cl = null; bool finish = false; Task task = null; bool connected = false; void clean() { Console.WriteLine("conn lost + "); connected = false; Console.WriteLine("connection is down"); reconn(); } void rd(Rec data) { task = new Task(() => { Console.WriteLine("sen task started"); long p = data.seq; while (p < stream.Length) { if (!connected) { Console.WriteLine("sen task ended"); return; } long blockSize = Math.Min(65536, stream.Length - p); stream.Seek(p, SeekOrigin.Begin); byte[] b = new byte[blockSize]; stream.Read(b, 0, (int)blockSize); p += blockSize; Data d = new Data(b); Console.WriteLine("sen task send"); leaf.Send(d); Console.WriteLine("sen task send, done"); Console.WriteLine($"{blockSize} bytes sent, total {p} sent"); Thread.Sleep(15); } Console.WriteLine("sen task fined"); done.Send(new Done()); }); task.Start(); } void fin(Done d) => finish = true; // client.ConnectionLost += clean; rec.NewData += rd; done.NewData += fin; void reconn() { while (true) { if (connected) { return; } try { Console.WriteLine("waiting..."); DynamicRemoteClient cl = listener.Accept(); if (app != null) { app.Dispose(); } app = new ApplicationConnectionManager(cl, tree, 1000, 4000); app.ConnectionLost += clean; cl.Activate(); //cl = listener.AcceptWsClient(); connected = true; Console.WriteLine("accepted! " /* + cl.Client.RemoteEndPoint.ToString()*/); } catch (Exception e) { Console.WriteLine("network error"); Thread.Sleep(1000); continue; } } } reconn(); while (true) { if (finish) { Console.WriteLine("finished!!"); break; } else { Thread.Sleep(500); } } }
private void ListenerTask() { while (true) { Log("trying to accept a new client ..."); DynamicRemoteClient remoteClient = null; try { remoteClient = listener.Accept(); } catch { Log("unable to accept client", LogType.ERROR); Thread.Sleep(2000); continue; } ProtocolTree tree = new ProtocolTree(); DummyHandler <DummyProtocol> treeRoot = new DummyHandler <DummyProtocol>(); LeafProtocolHandler <AuthenticationProtocol> authHandler = new LeafProtocolHandler <AuthenticationProtocol>(); tree.Register(treeRoot); tree.Register(authHandler); tree.Entry(treeRoot); tree.ConnectToLeaf(treeRoot, authHandler); ApplicationConnectionManager app = new ApplicationConnectionManager(remoteClient, tree, new DummyProvider(), 3000, 6000); applicationConnections.Add(app, -1); authHandler.NewData += data => { if (data.statusCode != AuthenticationProtocol.StatusCode.Ack) { Log("invalid auth status code: ACK", LogType.ERROR); return; } void accept() { long resumeToken = 0; if (!resumeTokens.ContainsKey(data.interfaceId)) { resumeToken = Rnd64(); resumeTokens.Add(data.interfaceId, resumeToken); } else { resumeTokens[data.interfaceId] = resumeTokens[data.interfaceId]; } Log($"accept the client {data.interfaceId}, token = {resumeToken}"); authHandler.Send(new AuthenticationProtocol { statusCode = AuthenticationProtocol.StatusCode.Accept, resumeToken = resumeToken }); } void reject(string reason) { authHandler.Send(new AuthenticationProtocol { statusCode = AuthenticationProtocol.StatusCode.Reject, reason = reason }); } if (data.interfaceId < 0 || data.interfaceId >= logic.MaxConnection) { Log($"reject the client since the interface {data.interfaceId} is not valie", LogType.WARNING); reject("invalid interface id"); return; } lock (interfaceLock) { bool IsExistingUser = connectionInterruptTimers.ContainsKey(data.interfaceId); if (IsExistingUser && data.resumeToken != resumeTokens[data.interfaceId]) { Log($"reject the client since the resume token {data.resumeToken} is not correct", LogType.WARNING); reject("wrong resume token"); return; } if (!serviceBackupData.connectionInterfaces[data.interfaceId].Enabled && !IsExistingUser) { Log($"reject the client since the interface {data.interfaceId} is not available", LogType.WARNING); reject("interface is not available"); return; } if (serviceBackupData.connectionInterfaces[data.interfaceId].Ticket != data.ticket) { Log($"reject the client since the ticket {data.ticket} is not correct", LogType.WARNING); reject("invalid ticket"); return; } Log("auth is valid, accept the client"); accept(); tree.Connect(treeRoot, logic.GetProtocolTree(data.interfaceId)); applicationConnections[app] = data.interfaceId; if (IsExistingUser) { Log($"client with id {data.interfaceId} comes back", LogType.WARNING); RemoveTimer(data.interfaceId); logic.OnClientResume(data.interfaceId); } else { Log($"calling logic OnClientEnter and close interface {data.interfaceId}"); CloseInterface(data.interfaceId); logic.OnClientEnter(data.interfaceId); } } }; app.ConnectionLost += () => { app.Dispose(); int id = applicationConnections[app]; applicationConnections.Remove(app); Log($"client {id} is leaving", LogType.WARNING); if (id >= 0) { logic.GetProtocolTree(id).Detach(); if (logic.CanResume(id)) { System.Timers.Timer timer = new System.Timers.Timer(20000) { AutoReset = false }; timer.Elapsed += (s, e) => { lock (interfaceLock) { Log($"client {id} leave permanently", LogType.WARNING); timer.Dispose(); connectionInterruptTimers.Remove(id); resumeTokens.Remove(id); logic.OnClientLeave(id); } }; timer.Start(); connectionInterruptTimers.Add(id, timer); logic.OnClientDisconnect(id); Log($"start timer to wait for client {id} to come back", LogType.WARNING); } else { logic.OnClientLeave(id); Log($"client {id} leave permanently since logic cannot resume now", LogType.WARNING); } } }; remoteClient.Activate(); Logger.Log("sending auth data ...", "ServiceHost"); authHandler.Send(new AuthenticationProtocol { statusCode = AuthenticationProtocol.StatusCode.Request }); } }