/// <summary> /// get the next item. please invoke Reset() at the first time. /// if overflow, then:<para/> /// if timeout = TimeSpan.MinValue, it means not wait the data coming.<para/> /// if not wait, return null.<para/> /// if wait, wait util data arrived or timeout. /// </summary> /// <param name="timeout"> /// a TimeSpan struct that specifies the timeout to wait for next data coming.<para/> /// if timeout = TimeSpan.MinValue, it means not wait the data coming. /// </param> /// <returns> /// a SequenceToken object that indicates the first item. /// </returns> /// <exception cref="ObjectDisposedException"> /// thrown when this object is disposed. /// </exception> /// <exception cref="TimeoutException"> /// thrown when it is timeout when waiting for data coming. /// </exception> public SequenceItem Next(TimeSpan timeout) { if (disposed) { throw new ObjectDisposedException("DataSequence"); } // a bool value that indicates whether need to wait for data coming when data is not enough. // if true, wait util timeout; otherwise, return null if no data. bool notNeedToWait = (timeout == TimeSpan.MinValue); // the end time for operation. DateTime endTime = DateTime.Now; TimeSpan currentTimeout = timeout; // if donot wait, the timeout is not used. // if need to wait, calculate the timeout. if (!notNeedToWait) { endTime += timeout; } while (true) { lock (this.objectLock) { // try to return the next new item. SequenceItem item = this.GetNextNewItem(); if (item != null) { return(item); } // all items in sequence are not valid, wait for more if needed. // if timeout is TimeSpan.MinValue, user does not accept wait, // return null and donot reset the index. if (timeout == TimeSpan.MinValue) { return(null); } // need to wait for next item coming. this.receivedEvent.Reset(); } // it's timeout when wait for data coming, reset the index and throw exception. if (currentTimeout.Ticks < 0 || !this.receivedEvent.WaitOne(currentTimeout, false)) { throw new TimeoutException("it is timeout when DataSequence waiting for data coming"); } // update the current timeout and get data in the next loop. currentTimeout = endTime - DateTime.Now; } }
/// <summary> /// get next valid item. /// </summary> /// <returns> /// a SeuqenceItem object that does not exists in the owners. /// </returns> private SequenceItem GetNextNewItem() { while (this.index < this.sequence.Count) { SequenceItem item = this.sequence[this.index++]; // if current item is not the previous items, return. // otherwise, search for next item. if (!this.visitedOwners.Contains(item.Source)) { this.visitedOwners.Add(item.Source); return(item); } } return(null); }
/// <summary> /// expect packet from transport.<para/> /// the transport must be a TcpServer or NetbiosServer. /// </summary> /// <param name="host"> /// an IGetAnyBytesVisitor interface that specifies the host of visitor. /// </param> /// <param name="sequence"> /// a DataSequence object that manages the sequence information of multiple clients. /// </param> /// <param name="timeout"> /// a TimeSpan object that indicates the timeout to expect event. /// </param> /// <param name="maxCount"> /// an int value that specifies the maximum count of bytes to get. /// </param> /// <param name="remoteEndPoint"> /// an object that specifies the remote endpoint expected packet. /// </param> /// <param name="localEndPoint"> /// an object that indicates the local endpoint received packet at. /// </param> /// <returns> /// a StackPacket object that specifies the received packet.<para/> /// if all buffer is closed in this while, and required to return if all buffer is closed, return null.<para/> /// otherwise never return null, if no packets coming in timespan, throw exception. /// </returns> public static byte[] Visit( IVisitorGetAnyBytes host, DataSequence sequence, TimeSpan timeout, int maxCount, out object remoteEndPoint, out object localEndPoint) { if (maxCount < 0) { throw new ArgumentException("max count must not be negative", "maxCount"); } sequence.Reset(); DateTime endTime = DateTime.Now + timeout; TimeSpan currentTimeout = timeout; while (true) { SequenceItem item = sequence.Next(currentTimeout); // skip event if (item.Source is TransportEvent) { currentTimeout = endTime - DateTime.Now; continue; } byte[] data = host.GetBytes(maxCount, item.Source, out remoteEndPoint, out localEndPoint); if (data == null) { throw new InvalidOperationException("invalid data received from client."); } sequence.Consume(item.Source, data.Length); return(data); } }
/// <summary> /// expect packet from transport.<para/> /// the transport must be a TcpServer or NetbiosServer. /// </summary> /// <param name="host"> /// an IVisitorGetAnyPacket interface that specifies the host of visitor. /// </param> /// <param name="eventQueue"> /// a SyncFilterQueue<TransportEvent> that specifies the queue to store event. /// </param> /// <param name="sequence"> /// a DataSequence object that manages the sequence information of multiple clients. /// </param> /// <param name="timeout"> /// a TimeSpan object that indicates the timeout to expect event. /// </param> /// <param name="skipEvent"> /// a bool value that specifies whether skip the event.<para/> /// if true, just wait for packet coming; otherwise, both data and event will return. /// </param> /// <returns> /// a StackPacket object that specifies the received packet.<para/> /// if all buffer is closed in this while, and required to return if all buffer is closed, return null.<para/> /// otherwise never return null, if no packets coming in timespan, throw exception. /// </returns> public static TransportEvent Visit( IVisitorGetAnyData host, SyncFilterQueue <TransportEvent> eventQueue, DataSequence sequence, TimeSpan timeout, bool skipEvent) { // the end time for operation. DateTime endTime = DateTime.Now + timeout; TimeSpan currentTimeout = timeout; while (true) { sequence.Reset(); // try to decode packet from all clients in sequence. while (true) { SequenceItem item = sequence.Next(TimeSpan.MinValue); // all item in the sequences returned if (item == null) { break; } TransportEvent transportEvent = item.Source as TransportEvent; // if event arrived and donot skip the event, return the event directly. if (transportEvent != null) { if (skipEvent) { continue; } sequence.Remove(transportEvent); Utility.Remove(eventQueue, transportEvent); return(transportEvent); } object remoteEndPoint; object localEndPoint; host.VisitorGetEndPoint(item.Source, out remoteEndPoint, out localEndPoint); int consumedLength = 0; StackPacket packet = null; try { // set timeout to zero, must not wait for more data. // if timeout, process next. packet = host.VisitorDecodePackets( item.Source, remoteEndPoint, localEndPoint, out consumedLength); // remove the sequence information in data sequence. sequence.Consume(item.Source, consumedLength); if (packet != null) { TcpServerConnection connection = item.Source as TcpServerConnection; if (connection != null) { return(connection.VisitorCreateTransportEvent(EventType.ReceivedPacket, packet)); } else { return(new TransportEvent(EventType.ReceivedPacket, remoteEndPoint, localEndPoint, packet)); } } } // skip timeout of any host. catch (TimeoutException) { } } // waiting for next data coming. sequence.Next(currentTimeout); currentTimeout = endTime - DateTime.Now; } }