데이터를 순차적으로 읽거나 쓸 수 있는 버퍼입니다. 데이터 쓰기의 경우, 버퍼가 부족하면 자동으로 증가시킵니다. 데이터 읽기의 경우, 쓰기된 크기 이상으로 읽어들일 수 없습니다.
        public bool Dispatch(StreamBuffer buffer)
        {
            var responses = new List<Data>();

            lock (_listResponseAction)
            {
                foreach (var data in _listResponseAction)
                    responses.Add(data);
            }

            foreach (var data in responses)
            {
                if (data.Predicate(buffer) == true)
                {
                    lock (_listResponseAction)
                        _listResponseAction.Remove(data);

                    var result = new IOEventResult(_session, IOEventType.Read,
                                                   buffer.Buffer, 0, buffer.WrittenBytes, AegisResult.Ok);
                    data.Dispatcher(result);
                    return true;
                }
            }

            return false;
        }
        public void SendPacket(StreamBuffer buffer, Action<StreamBuffer> onSent = null)
        {
            try
            {
                lock (_session)
                {
                    if (_session.Socket == null)
                        return;

                    //  ReadIndex가 OnSocket_Send에서 사용되므로 ReadIndex를 초기화해야 한다.
                    buffer.ResetReadIndex();

                    SocketAsyncEventArgs saea = new SocketAsyncEventArgs();
                    saea.Completed += SendComplete;
                    saea.SetBuffer(buffer.Buffer, 0, buffer.WrittenBytes);
                    if (onSent != null)
                        saea.UserToken = new NetworkSendToken(buffer, onSent);

                    if (_session.Socket.SendAsync(saea) == false)
                        ReceiveComplete(null, saea);
                }
            }
            catch (SocketException)
            {
            }
            catch (Exception e)
            {
                Logger.Err(LogMask.Aegis, e.ToString());
            }
        }
        public void SendPacket(StreamBuffer buffer, Action<StreamBuffer> onSent = null)
        {
            try
            {
                lock (_session)
                {
                    if (_session.Socket != null)
                    {
                        //  ReadIndex가 OnSocket_Send에서 사용되므로 ReadIndex를 초기화해야 한다.
                        buffer.ResetReadIndex();

                        if (onSent == null)
                            _session.Socket.BeginSend(buffer.Buffer, 0, buffer.WrittenBytes, SocketFlags.None, Socket_Send, null);
                        else
                            _session.Socket.BeginSend(buffer.Buffer, 0, buffer.WrittenBytes, SocketFlags.None, Socket_Send,
                                             new NetworkSendToken(buffer, onSent));
                    }
                }
            }
            catch (SocketException)
            {
            }
            catch (Exception e)
            {
                Logger.Err(LogMask.Aegis, e.ToString());
            }
        }
        public StreamBuffer(StreamBuffer source)
        {
            ReadBytes = 0;
            WrittenBytes = 0;

            Capacity(source.WrittenBytes);
            Write(source.Buffer, 0, source.WrittenBytes);
        }
        public StreamBuffer(StreamBuffer source, int index, int size)
        {
            ReadBytes = 0;
            WrittenBytes = 0;

            Capacity(size);
            Write(source.Buffer, index, size);
        }
Beispiel #6
0
 public void Send(StreamBuffer buffer)
 {
     lock (this)
     {
         var socket = _socket;
         socket?.BeginSendTo(buffer.Buffer, 0, buffer.WrittenBytes, SocketFlags.None, _endPoint, Socket_Send, null);
     }
 }
        public SessionMethodAsyncEvent(Session session)
        {
            _session = session;
            _receivedBuffer = new StreamBuffer(2048);
            _dispatchBuffer = new StreamBuffer(2048);

            _saeaRecv = new SocketAsyncEventArgs();
            _saeaRecv.Completed += ReceiveComplete;
            _responseSelector = new ResponseSelector(_session);
        }
        public virtual StreamBuffer Clone()
        {
            StreamBuffer newStream = new StreamBuffer(this);
            newStream.ReadBytes = ReadBytes;
            newStream.WrittenBytes = WrittenBytes;

            return newStream;
        }
        public static ulong GetUInt64(StreamBuffer source, int readIndex)
        {
            if (readIndex + sizeof(ulong) > source.WrittenBytes)
                throw new AegisException(AegisResult.BufferUnderflow, "No more readable buffer.");

            return BitConverter.ToUInt64(source.Buffer, readIndex);
        }
Beispiel #10
0
        public static string GetStringAsUtf16(StreamBuffer source, int readIndex)
        {
            int i, stringBytes = 0;
            for (i = readIndex; i < source.WrittenBytes; i += 2)
            {
                if (source.Buffer[i + 0] == 0
                    && source.Buffer[i + 1] == 0)
                    break;

                stringBytes += 2;

                if (readIndex + stringBytes + 2 > source.WrittenBytes)
                    throw new AegisException(AegisResult.BufferUnderflow, "No more readable buffer.");
            }

            //  String으로 변환할 때 Null terminate를 포함시켜서는 안된다.
            return Encoding.Unicode.GetString(source.Buffer, readIndex, stringBytes);
        }
Beispiel #11
0
 /// <summary>
 /// 패킷을 전송합니다.
 /// </summary>
 /// <param name="buffer">전송할 데이터가 담긴 StreamBuffer</param>
 /// <param name="onSent">패킷 전송이 완료된 후 호출할 Action</param>
 public virtual void SendPacket(StreamBuffer buffer, Action<StreamBuffer> onSent = null)
 {
     _method.SendPacket(buffer, onSent);
 }
Beispiel #12
0
        public void Write(StreamBuffer source, int sourceIndex)
        {
            if (sourceIndex >= source.WrittenBytes)
                throw new AegisException(AegisResult.BufferUnderflow, "The argument index(={0}) is larger then source size(={1}).", sourceIndex, source.WrittenBytes);

            int copyBytes = source.WrittenBytes - sourceIndex;
            if (WrittenBytes + copyBytes > BufferSize)
                Resize(BufferSize + copyBytes);

            Array.Copy(source.Buffer, sourceIndex, Buffer, WrittenBytes, copyBytes);
            WrittenBytes += copyBytes;

            OnWritten();
        }
Beispiel #13
0
        /// <summary>
        /// 패킷 버퍼를 초기화하고 source 데이터를 저장합니다. Packet Header의 Size는 source 버퍼의 헤더값이 사용됩니다.
        /// </summary>
        /// <param name="source">저장할 데이터</param>
        public virtual void Clear(StreamBuffer source)
        {
            if (source.BufferSize < HeaderSize)
                throw new AegisException(AegisResult.InvalidArgument, "The source size must be at lest {0} bytes.", HeaderSize);

            base.Clear();
            Write(source.Buffer, 0, source.WrittenBytes);
            Size = GetUInt16(0);
        }
Beispiel #14
0
        /// <summary>
        /// 수신된 데이터가 유효한 패킷인지 여부를 확인합니다.
        /// 유효한 패킷으로 판단되면 packetSize에 이 패킷의 정확한 크기를 입력하고 true를 반환해야 합니다.
        /// </summary>
        /// <param name="buffer">수신된 데이터가 담긴 버퍼</param>
        /// <param name="packetSize">유효한 패킷의 크기</param>
        /// <returns>true를 반환하면 EventReceive 통해 수신된 데이터가 전달됩니다.</returns>
        public static bool IsValidPacket(StreamBuffer buffer, out int packetSize)
        {
            if (buffer.WrittenBytes < HeaderSize)
            {
                packetSize = 0;
                return false;
            }

            //  최초 2바이트를 수신할 패킷의 크기로 처리
            packetSize = buffer.GetUInt16(0);
            return (packetSize > 0 && buffer.WrittenBytes >= packetSize);
        }
Beispiel #15
0
        /// <summary>
        /// 지정된 버퍼에서 PacketId 값을 가져옵니다.
        /// buffer는 패킷 헤더가 온전히 포함된 데이터로 지정되어야 합니다.
        /// </summary>
        /// <param name="buffer">패킷 데이터가 담긴 버퍼</param>
        /// <returns>패킷의 PacketId를 반환합니다.</returns>
        public static ushort GetPacketId(StreamBuffer buffer)
        {
            if (buffer.Buffer.Length < 4)
                return 0;

            return BitConverter.ToUInt16(buffer.Buffer, 2);
        }
Beispiel #16
0
 /// <summary>
 /// StreamBuffer의 데이터를 복사하여 패킷을 생성합니다.
 /// </summary>
 /// <param name="source">복사할 데이터가 담긴 StreamBuffer 객체</param>
 public SecurePacket(StreamBuffer source)
 {
     Write(source.Buffer, 0, source.WrittenBytes);
 }
Beispiel #17
0
 internal void OnReceived(StreamBuffer buffer)
 {
     if (_methodSelector?.Dispatch(buffer) == false)
         EventReceive?.Invoke(new IOEventResult(this, IOEventType.Read, buffer.Buffer, 0, buffer.WrittenBytes, AegisResult.Ok));
 }
Beispiel #18
0
 /// <summary>
 /// 패킷을 전송하고, 특정 패킷이 수신될 경우 dispatcher에 지정된 핸들러를 실행합니다.
 /// 이 기능은 AwaitableMethod보다는 빠르지만, 동시에 많이 호출될 경우 성능이 저하될 수 있습니다.
 /// </summary>
 /// <param name="buffer">전송할 데이터가 담긴 StreamBuffer</param>
 /// <param name="predicate">dispatcher에 지정된 핸들러를 호출할 것인지 여부를 판단하는 함수를 지정합니다.</param>
 /// <param name="dispatcher">실행될 함수를 지정합니다.</param>
 /// <param name="onSent">패킷 전송이 완료된 후 호출할 Action</param>
 public virtual void SendPacket(StreamBuffer buffer, PacketPredicate predicate, IOEventHandler dispatcher, Action<StreamBuffer> onSent = null)
 {
     _method.SendPacket(buffer, predicate, dispatcher, onSent);
 }
Beispiel #19
0
        public void Write(StreamBuffer source)
        {
            int srcSize = source.WrittenBytes;
            if (WrittenBytes + srcSize > BufferSize)
                Resize(BufferSize + srcSize);

            Array.Copy(source.Buffer, 0, Buffer, WrittenBytes, srcSize);
            WrittenBytes += srcSize;

            OnWritten();
        }
        public void SendPacket(StreamBuffer buffer, PacketPredicate predicate, IOEventHandler dispatcher, Action<StreamBuffer> onSent = null)
        {
            if (predicate == null || dispatcher == null)
                throw new AegisException(AegisResult.InvalidArgument, "The argument predicate and dispatcher cannot be null.");

            try
            {
                lock (_session)
                {
                    if (_session.Socket == null)
                        return;

                    //  ReadIndex가 OnSocket_Send에서 사용되므로 ReadIndex를 초기화해야 한다.
                    buffer.ResetReadIndex();

                    SocketAsyncEventArgs saea = new SocketAsyncEventArgs();
                    saea.Completed += SendComplete;
                    saea.SetBuffer(buffer.Buffer, 0, buffer.WrittenBytes);
                    if (onSent != null)
                        saea.UserToken = new NetworkSendToken(buffer, onSent);

                    _responseSelector.Add(predicate, dispatcher);

                    if (_session.Socket.SendAsync(saea) == false)
                        ReceiveComplete(null, saea);
                }
            }
            catch (SocketException)
            {
            }
            catch (Exception e)
            {
                Logger.Err(LogMask.Aegis, e.ToString());
            }
        }
Beispiel #21
0
        public void Write(StreamBuffer source, int sourceIndex, int length)
        {
            if (sourceIndex + length > source.WrittenBytes)
                throw new AegisException(AegisResult.BufferUnderflow, "The source buffer is small then requested.");

            int copyBytes = length;
            if (WrittenBytes + copyBytes > BufferSize)
                Resize(BufferSize + copyBytes);

            Array.Copy(source.Buffer, sourceIndex, Buffer, WrittenBytes, copyBytes);
            WrittenBytes += copyBytes;

            OnWritten();
        }
        public void SendPacket(StreamBuffer buffer, PacketPredicate predicate, IOEventHandler dispatcher, Action<StreamBuffer> onSent = null)
        {
            if (predicate == null || dispatcher == null)
                throw new AegisException(AegisResult.InvalidArgument, "The argument predicate and dispatcher cannot be null.");

            try
            {
                lock (_session)
                {
                    _responseSelector.Add(predicate, dispatcher);
                    if (_session.Socket != null)
                    {
                        //  ReadIndex가 OnSocket_Send에서 사용되므로 ReadIndex를 초기화해야 한다.
                        buffer.ResetReadIndex();

                        if (onSent == null)
                            _session.Socket.BeginSend(buffer.Buffer, 0, buffer.WrittenBytes, SocketFlags.None, Socket_Send, null);
                        else
                            _session.Socket.BeginSend(buffer.Buffer, 0, buffer.WrittenBytes, SocketFlags.None, Socket_Send,
                                             new NetworkSendToken(buffer, onSent));
                    }
                }
            }
            catch (SocketException)
            {
            }
            catch (Exception e)
            {
                Logger.Err(LogMask.Aegis, e.ToString());
            }
        }
        private void ReceiveComplete(object sender, SocketAsyncEventArgs saea)
        {
            try
            {
                lock (_session)
                {
                    //  transBytes가 0이면 원격지 혹은 네트워크에 의해 연결이 끊긴 상태
                    int transBytes = saea.BytesTransferred;
                    if (transBytes == 0)
                    {
                        _session.Close(AegisResult.ClosedByRemote);
                        return;
                    }

                    _receivedBuffer.Write(transBytes);
                    while (_receivedBuffer.ReadableSize > 0)
                    {
                        //  패킷 하나가 정상적으로 수신되었는지 확인
                        int packetSize;
                        StreamBuffer tmpBuffer = new StreamBuffer(_receivedBuffer, _receivedBuffer.ReadBytes, _receivedBuffer.ReadableSize);
                        if (_session.PacketValidator == null ||
                            _session.PacketValidator(tmpBuffer, out packetSize) == false)
                            break;

                        try
                        {
                            //  수신 이벤트 처리 중 종료 이벤트가 발생한 경우
                            if (_session.Socket == null)
                                return;

                            //  수신버퍼에서 제거
                            _receivedBuffer.Read(packetSize);

                            //  수신처리(Dispatch)
                            StreamBuffer dispatchBuffer = new StreamBuffer(tmpBuffer, 0, packetSize);
                            SpinWorker.Dispatch(() =>
                            {
                                if (_responseSelector.Dispatch(dispatchBuffer) == false)
                                    _session.OnReceived(dispatchBuffer);
                            });
                        }
                        catch (Exception e)
                        {
                            Logger.Err(LogMask.Aegis, e.ToString());
                        }
                    }

                    //  처리된 패킷을 버퍼에서 제거
                    _receivedBuffer.PopReadBuffer();

                    //  ReceiveBuffer의 안정적인 처리를 위해 작업이 끝난 후에 다시 수신대기
                    WaitForReceive();
                }
            }
            catch (SocketException)
            {
                _session.Close(AegisResult.ClosedByRemote);
            }
            catch (Exception e)
            {
                Logger.Err(LogMask.Aegis, e.ToString());
            }
        }
Beispiel #24
0
        public static bool GetBoolean(StreamBuffer source, int readIndex)
        {
            if (readIndex + sizeof(byte) > source.WrittenBytes)
                throw new AegisException(AegisResult.BufferUnderflow, "No more readable buffer.");

            return (source.Buffer[readIndex] == 1);
        }
Beispiel #25
0
        public static sbyte GetSByte(StreamBuffer source, int readIndex)
        {
            if (readIndex + sizeof(sbyte) > source.WrittenBytes)
                throw new AegisException(AegisResult.BufferUnderflow, "No more readable buffer.");

            return (sbyte)source.Buffer[readIndex];
        }
 public SessionMethodAsyncResult(Session session)
 {
     _session = session;
     _receivedBuffer = new StreamBuffer(2048);
     _responseSelector = new ResponseSelector(_session);
 }