/// <summary> /// HTTP 响应头部输出 /// </summary> /// <param name="response"></param> /// <returns></returns> private bool responseHeader(ref Response response) { try { if (!response.IsFile) { ResponseError(ResponseState.NotFound404); return true; } System.Net.Sockets.Socket socket; ResponseFlag responseFlag = response.Flag; if (response.Body.Length != 0 && Header.IsKeepAlive != 0 && (responseFlag & ResponseFlag.HeaderSize) != 0 && Header.IsRange == 0 && Header.Method != MethodType.HEAD) { if ((socket = Socket) == null) return false; Data = response.Body; Data.MoveStart(-response.HeaderSize); SendType = SendType.Next; Timeout = Config.GetTimeout(Data.Length); #if DOTNET2 SocketError socketError; IAsyncResult async = socket.BeginSend(Data.Array, Data.Start, Data.Length, SocketFlags.None, out socketError, onSendAsyncCallback, socket); if (socketError == SocketError.Success) { if (!async.CompletedSynchronously) Http.Header.ReceiveTimeout.Push(this, socket); return true; } return false; #else while (Interlocked.CompareExchange(ref sendAsyncLock, 1, 0) != 0) Thread.Sleep(0); sendAsyncEventArgs.SetBuffer(Data.Array, Data.Start, Data.Length); if (socket.SendAsync(sendAsyncEventArgs)) { Http.Header.ReceiveTimeout.Push(this, socket); Interlocked.Exchange(ref sendAsyncLock, 0); return true; } sendAsyncLock = 0; if (--sendDepth == 0) { sendDepth = maxSendDepth; OnSendTask.Task.Add(this); return true; } return onSend(); #endif } ResponseSize = response.BodySize; fixed (byte* headerBufferFixed = Header.Buffer.Buffer) { byte* responseSizeFixed = headerBufferFixed + (Header.Buffer.StartIndex + Http.Header.ReceiveBufferSize); RangeLength responseSizeIndex, bodySizeIndex = new RangeLength(), rangeStartIndex = new RangeLength(), rangeEndIndex = new RangeLength(); ResponseState state = response.ResponseState; if (Header.IsRange != 0 && (responseFlag & ResponseFlag.IsPool) != 0) { if (Header.IsFormatRange != 0 || Header.FormatRange(ResponseSize)) { if (state == ResponseState.Ok200) { long rangeStart = Header.RangeStart, rangeEnd = Header.RangeEnd; rangeStartIndex = Number.ToBytes((ulong)rangeStart, responseSizeFixed + 20 * 2); rangeEndIndex = Number.ToBytes((ulong)rangeEnd, responseSizeFixed + 20 * 3); bodySizeIndex = Number.ToBytes((ulong)ResponseSize, responseSizeFixed + 20); response.State = state = ResponseState.PartialContent206; ResponseSize = Header.RangeSize; } } else { ResponseSize = 0; ResponseError(ResponseState.RangeNotSatisfiable416); return true; } } if ((ulong)ResponseSize < 10) { *responseSizeFixed = (byte)((int)ResponseSize + '0'); responseSizeIndex = new RangeLength(0, 1); } else responseSizeIndex = Number.ToBytes((ulong)ResponseSize, responseSizeFixed); ResponseStateAttribute stateAttribute = EnumAttribute<ResponseState, ResponseStateAttribute>.Array((byte)state); if (stateAttribute == null) stateAttribute = EnumAttribute<ResponseState, ResponseStateAttribute>.Array((byte)ResponseState.ServerError500); int index = httpVersionSize + stateAttribute.Text.Length + contentLengthSize + responseSizeIndex.Length + 2 + 2; if (state == ResponseState.PartialContent206) { index += rangeSize + rangeStartIndex.Length + rangeEndIndex.Length + bodySizeIndex.Length + 2 + 2; } Cookie cookie = null; SubBuffer.PoolBufferFull buffer = GetBuffer(index = GetResponseHeaderIndex(response, index, ref cookie)); fixed (byte* bufferFixed = buffer.Buffer) { byte* bufferStart = bufferFixed + buffer.StartIndex, write = bufferStart + httpVersionSize; writeHttpVersion(bufferStart); stateAttribute.Write(write); writeContentLength(write += stateAttribute.Text.Length); Memory.SimpleCopyNotNull64(responseSizeFixed + responseSizeIndex.Start, write += contentLengthSize, responseSizeIndex.Length); *(short*)(write += responseSizeIndex.Length) = 0x0a0d; write += sizeof(short); if (state == ResponseState.PartialContent206) { writeRange(write); Memory.SimpleCopyNotNull64(responseSizeFixed + (rangeStartIndex.Start + 20 * 2), write += rangeSize, rangeStartIndex.Length); *(write += rangeStartIndex.Length) = (byte)'-'; Memory.SimpleCopyNotNull64(responseSizeFixed + (rangeEndIndex.Start + 20 * 3), ++write, rangeEndIndex.Length); *(write += rangeEndIndex.Length) = (byte)'/'; Memory.SimpleCopyNotNull64(responseSizeFixed + (bodySizeIndex.Start + 20), ++write, bodySizeIndex.Length); *(short*)(write += bodySizeIndex.Length) = 0x0a0d; write += sizeof(short); } index = (int)(CreateResponseHeader(response, cookie, write, index) - bufferStart); // if (checkIndex != index) // { // Server.RegisterServer.TcpServer.Log.add(Log.Type.Fatal, "responseHeader checkIndex[" + checkIndex.toString() + "] != index[" + index.toString() + @"] //" + System.Text.Encoding.ASCII.GetString(buffer.Buffer, buffer.StartIndex, index)); // } if (ResponseSize != 0) { switch (response.Type) { case ResponseType.ByteArray: if (buffer.Length - index >= (int)ResponseSize) { System.Buffer.BlockCopy(response.Body.Array, state == ResponseState.PartialContent206 ? (int)Header.RangeStart : 0, buffer.Buffer, buffer.StartIndex + index, (int)ResponseSize); index += (int)ResponseSize; ResponseSize = 0; } break; case ResponseType.SubByteArray: if (Header.IsKeepAlive != 0 && (responseFlag & ResponseFlag.CanHeaderSize) != 0 && index <= response.Body.Start && Header.IsRange == 0) { if ((socket = Socket) == null) return false; fixed (byte* bodyFixed = response.Body.Array) Memory.CopyNotNull(bufferStart, bodyFixed + response.Body.Start - index, index); response.SetHeaderSize(index); Data = response.Body; Data.MoveStart(-response.HeaderSize); SendType = SendType.Next; Timeout = Config.GetTimeout(Data.Length); #if DOTNET2 SocketError socketError; IAsyncResult async = socket.BeginSend(Data.Array, Data.Start, Data.Length, SocketFlags.None, out socketError, onSendAsyncCallback, socket); if (socketError == SocketError.Success) { if (!async.CompletedSynchronously) Http.Header.ReceiveTimeout.Push(this, socket); return true; } return false; #else while (Interlocked.CompareExchange(ref sendAsyncLock, 1, 0) != 0) Thread.Sleep(0); sendAsyncEventArgs.SetBuffer(Data.Array, Data.Start, Data.Length); if (socket.SendAsync(sendAsyncEventArgs)) { Http.Header.ReceiveTimeout.Push(this, socket); Interlocked.Exchange(ref sendAsyncLock, 0); return true; } sendAsyncLock = 0; if (--sendDepth == 0) { sendDepth = maxSendDepth; OnSendTask.Task.Add(this); return true; } return onSend(); #endif } goto COPY; case ResponseType.SubBuffer: COPY: if (buffer.Length - index >= (int)ResponseSize) { System.Buffer.BlockCopy(response.Body.Array, state == ResponseState.PartialContent206 ? response.Body.Start + (int)Header.RangeStart : response.Body.Start, buffer.Buffer, buffer.StartIndex + index, (int)ResponseSize); index += (int)ResponseSize; ResponseSize = 0; } break; } } } if ((socket = Socket) != null) { if (ResponseSize == 0) SendType = SendType.Next; else { this.HttpResponse = response; SendType = SendType.Body; response = null; } Data.Set(buffer.Buffer, buffer.StartIndex, index); Timeout = Config.GetTimeout(Data.Length); #if DOTNET2 SocketError socketError; IAsyncResult async = socket.BeginSend(Data.Array, Data.Start, index, SocketFlags.None, out socketError, onSendAsyncCallback, socket); if (socketError == SocketError.Success) { if (!async.CompletedSynchronously) Http.Header.ReceiveTimeout.Push(this, socket); return true; } return false; #else while (Interlocked.CompareExchange(ref sendAsyncLock, 1, 0) != 0) Thread.Sleep(0); sendAsyncEventArgs.SetBuffer(Data.Array, Data.Start, index); if (socket.SendAsync(sendAsyncEventArgs)) { Http.Header.ReceiveTimeout.Push(this, socket); Interlocked.Exchange(ref sendAsyncLock, 0); return true; } sendAsyncLock = 0; if (--sendDepth == 0) { sendDepth = maxSendDepth; OnSendTask.Task.Add(this); return true; } return onSend(); #endif } } } catch (Exception error) { Server.RegisterServer.TcpServer.Log.Add(Log.LogType.Error, error); } finally { Http.Response.Push(ref response); } return false; }
/// <summary> /// 获取数据包索引信息 /// </summary> /// <param name="identity">需要定位的数据标识</param> /// <param name="startIdentity"></param> /// <param name="fileIndex"></param> /// <returns></returns> internal bool GetIndex(ulong identity, ref ulong startIdentity, ref long fileIndex) { startIdentity = identity & (ulong.MaxValue - (DataCountPerFile - 1)); uint fileIdentity = (uint)identity & (DataCountPerFile - 1); if (fileIdentity == 0) { fileIndex = 0; return(true); } ulong baseIdentity = startIdentity; if (this.baseIdentity == startIdentity) { int length = indexs.Length; if (length > 1) { #region 二分查找当前数据文件数据包索引信息 int start = 0, average; PacketIndex[] indexArray = indexs.Array; do { if (identity > indexArray[average = start + ((length - start) >> 1)].Identity) { start = average + 1; } else { length = average; } }while (start != length); if (identity != indexArray[start].Identity) { --start; } indexArray[start].Get(out startIdentity, out fileIndex); if (this.baseIdentity == baseIdentity) { return(true); } #endregion } } FileInfo dataFileInfo = new FileInfo(GetFileName(identity)); if (dataFileInfo.Exists && dataFileInfo.Length != 0) { SubBuffer.PoolBufferFull buffer = default(SubBuffer.PoolBufferFull); SubBuffer.Pool.GetBuffer(ref buffer, createIndexBufferSize + sizeof(int)); try { fixed(byte *bufferFixed = buffer.GetFixedBuffer()) { byte *bufferStart = bufferFixed + buffer.StartIndex; #region 从索引数据文件获取数据包索引信息 FileInfo indexFileInfo = new FileInfo(getIndexFileName(identity)); if (indexFileInfo.Exists && indexFileInfo.Length >= sizeof(int) * 2) { uint lastFileIdentity = 0; fileIndex = 0; using (FileStream indexFileStream = new FileStream(indexFileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, createIndexBufferSize, FileOptions.None)) { do { int readSize = indexFileStream.Read(buffer.Buffer, buffer.StartIndex, createIndexBufferSize); if (readSize <= 0) { break; } byte *read = bufferStart, end = bufferStart + readSize; do { if (*(uint *)read < fileIdentity) { lastFileIdentity = *(uint *)read; fileIndex += *(int *)(read + sizeof(int)); } else { if (*(uint *)read == fileIdentity) { lastFileIdentity = *(uint *)read; fileIndex += *(int *)(read + sizeof(int)); } startIdentity = baseIdentity + lastFileIdentity; return(true); } }while ((read += sizeof(int) * 2) < end); }while (true); } startIdentity = baseIdentity + lastFileIdentity; return(true); } #endregion #region 从数据文件获取数据包索引信息 int bufferIndex = 0, dataSize; fileIndex = 0; startIdentity = baseIdentity; using (FileStream fileStream = new FileStream(dataFileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, createIndexBufferSize, FileOptions.None)) { long nextFileSize = fileStream.Length; do { int endBufferIndex = fileStream.Read(buffer.Buffer, buffer.StartIndex + bufferIndex, createIndexBufferSize - bufferIndex); nextFileSize -= endBufferIndex; endBufferIndex += bufferIndex - sizeof(int) * 3; bufferIndex = 0; do { byte *read = bufferStart + bufferIndex; dataSize = *(int *)read; ulong nextIdentity = startIdentity + *(uint *)(read + (dataSize < 0 ? sizeof(int) * 2 : sizeof(int))); if (nextIdentity >= identity) { if (nextIdentity == identity) { startIdentity = nextIdentity; bufferIndex += dataSize < 0 ? (-dataSize + PacketHeaderSize + sizeof(int)) : (dataSize + PacketHeaderSize); } fileIndex += bufferIndex; return(true); } startIdentity = nextIdentity; bufferIndex += dataSize < 0 ? (-dataSize + PacketHeaderSize + sizeof(int)) : (dataSize + PacketHeaderSize); }while (bufferIndex <= endBufferIndex); fileIndex += bufferIndex; switch (dataSize = bufferIndex - endBufferIndex) { case 1: case 2: case 3: *(ulong *)bufferStart = *(ulong *)(bufferStart + bufferIndex); *(uint *)(bufferStart + sizeof(ulong)) = *(uint *)(bufferStart + (bufferIndex + sizeof(ulong))); bufferIndex = sizeof(int) * 3 - dataSize; break; case 4: case 5: case 6: case 7: *(ulong *)bufferStart = *(ulong *)(bufferStart + bufferIndex); bufferIndex = sizeof(int) * 3 - dataSize; break; case 8: case 9: case 10: case 11: *(uint *)bufferStart = *(uint *)(bufferStart + bufferIndex); bufferIndex = sizeof(int) * 3 - dataSize; break; case 12: bufferIndex = 0; break; default: fileStream.Seek(dataSize -= sizeof(int) * 3, SeekOrigin.Current); nextFileSize -= dataSize; bufferIndex = 0; break; } }while (nextFileSize > 0); } return(true); #endregion } } finally { buffer.Free(); } } return(false); }
private void doCommand(ref SubBuffer.PoolBufferFull buffer) { SubArray<byte> data = new SubArray<byte> { Array = buffer.Buffer, Start = buffer.StartIndex, Length = dataSize }; doCommand(ref data); buffer.PoolBuffer.Free(); }
/// <summary> /// 初始化 /// </summary> internal void Start() { int isDisposed = 1; SubBuffer.PoolBufferFull buffer = default(SubBuffer.PoolBufferFull); try { if (checkStateFile()) { byte[] stateData = new byte[stateBufferSize]; stateFileStream = new FileStream(stateFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, stateBufferSize, FileOptions.None); stateFileStream.Seek(-stateBufferSize, SeekOrigin.End); stateFileStream.Read(stateData, 0, stateBufferSize); fixed(byte *stateDataFixed = stateData) { identity = *(ulong *)stateDataFixed; dataFileLength = *(long *)(stateDataFixed + sizeof(ulong)); } if (((uint)identity & (DataCountPerFile - 1)) == 0) { dataFileLength = 0; } if (dataFileLength == 0) { FileInfo dataFileInfo = new FileInfo(dataFileName); if (dataFileInfo.Exists) { if (dataFileInfo.Length == 0) { dataFileInfo.Delete(); } else { AutoCSer.IO.File.MoveBak(dataFileInfo.FullName); } } dataFileStream = new FileStream(dataFileInfo.FullName, FileMode.CreateNew, FileAccess.Write, FileShare.Read, bufferPool.Size, FileOptions.None); } else { FileInfo dataFileInfo = new FileInfo(dataFileName); if (!dataFileInfo.Exists) { Node.Cache.TcpServer.Log.Error("没有找到消息队列数据文件 " + dataFileInfo.FullName, LogLevel.Error | LogLevel.AutoCSer); return; } if (dataFileInfo.Length < dataFileLength) { Node.Cache.TcpServer.Log.Error("消息队列数据文件 " + dataFileInfo.FullName + " 大小错误 " + dataFileInfo.Length.toString() + " < " + dataFileLength.toString(), LogLevel.Error | LogLevel.AutoCSer); return; } dataFileStream = new FileStream(dataFileInfo.FullName, FileMode.Open, FileAccess.Write, FileShare.Read, bufferPool.Size, FileOptions.None); if (dataFileStream.Length > dataFileLength) { dataFileStream.SetLength(dataFileLength); dataFileStream.Flush(true); } dataFileStream.Seek(0, SeekOrigin.End); FileInfo indexFileInfo = new FileInfo(getIndexFileName(identity)); bufferPool.Get(ref buffer); fixed(byte *bufferFixed = buffer.GetFixedBuffer()) { byte *bufferStart = bufferFixed + buffer.StartIndex, end = bufferStart + buffer.Length; ulong baseIdentity = this.baseIdentity; if (indexFileInfo.Exists && indexFileInfo.Length >= sizeof(int) * 2) { #region 初始化数据文件数据包索引信息 int count = (int)(indexFileInfo.Length >> 3), index = 0; long fileIndex = 0; indexs = new LeftArray <PacketIndex>(count); PacketIndex[] indexArray = indexs.Array; using (FileStream indexFileStream = new FileStream(indexFileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferPool.Size, FileOptions.None)) { do { indexFileStream.Read(buffer.Buffer, buffer.StartIndex, buffer.Length); byte *read = bufferStart; do { indexArray[index].Set(baseIdentity + *(uint *)read, fileIndex += *(int *)(read + sizeof(int))); if (++index == count) { break; } }while ((read += sizeof(int) * 2) != end); }while (index != count); } while (index != 0) { if ((fileIndex = indexArray[--index].FileIndex) == dataFileLength) { if (indexArray[index].Identity == identity) { indexs.Length = index + 1; } break; } if (fileIndex < dataFileLength) { break; } } #endregion } if (indexs.Length == 0) { #region 重建数据文件数据包索引信息 if (indexs.Array.Length == 0) { indexs = new LeftArray <PacketIndex>(1 << 10); } indexs.Array[0].Set(baseIdentity); indexs.Length = 1; int bufferIndex = 0, readBufferSize = Math.Min(buffer.Length, createIndexBufferSize), bufferEndIndex, dataSize; long nextFileSize = dataFileLength, fileIndex = 0; using (FileStream fileStream = new FileStream(dataFileInfo.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, readBufferSize, FileOptions.None)) { readBufferSize -= sizeof(int); do { bufferEndIndex = fileStream.Read(buffer.Buffer, buffer.StartIndex + bufferIndex, readBufferSize - bufferIndex); nextFileSize -= bufferEndIndex; bufferEndIndex += bufferIndex - sizeof(int) * 3; bufferIndex = 0; do { byte *read = bufferStart + bufferIndex; dataSize = *(int *)read; if (dataSize < 0) { baseIdentity += *(uint *)(read + sizeof(int) * 2); bufferIndex += -dataSize + PacketHeaderSize + sizeof(int); } else { baseIdentity += *(uint *)(read + sizeof(int)); bufferIndex += dataSize + PacketHeaderSize; } indexs.PrepLength(1); indexs.Array[indexs.Length].Set(baseIdentity, fileIndex + bufferIndex); ++indexs.Length; }while (bufferIndex <= bufferEndIndex); fileIndex += bufferIndex; switch (dataSize = bufferIndex - bufferEndIndex) { case 1: case 2: case 3: *(ulong *)bufferStart = *(ulong *)(bufferStart + bufferIndex); *(uint *)(bufferStart + sizeof(ulong)) = *(uint *)(bufferStart + (bufferIndex + sizeof(ulong))); bufferIndex = sizeof(int) * 3 - dataSize; break; case 4: case 5: case 6: case 7: *(ulong *)bufferStart = *(ulong *)(bufferStart + bufferIndex); bufferIndex = sizeof(int) * 3 - dataSize; break; case 8: case 9: case 10: case 11: *(uint *)bufferStart = *(uint *)(bufferStart + bufferIndex); bufferIndex = sizeof(int) * 3 - dataSize; break; case 12: bufferIndex = 0; break; default: fileStream.Seek(dataSize -= sizeof(int) * 3, SeekOrigin.Current); nextFileSize -= dataSize; bufferIndex = 0; break; } }while (nextFileSize > 0); } #endregion } } } } else { stateFileStream = new FileStream(stateFileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read, stateBufferSize, FileOptions.None); FileInfo dataFileInfo = new FileInfo(dataFileName); if (dataFileInfo.Exists) { if (dataFileInfo.Length == 0) { dataFileInfo.Delete(); } else { AutoCSer.IO.File.MoveBak(dataFileInfo.FullName); } } dataFileStream = new FileStream(dataFileName, FileMode.CreateNew, FileAccess.Write, FileShare.Read, bufferPool.Size, FileOptions.None); } if (indexs.Array.Length == 0) { indexs = new LeftArray <PacketIndex>(1 << 10); } if (indexs.Length == 0) { indexs.Array[0].Set(baseIdentity); indexs.Length = 1; } writeHandle = write; StatePacketIndex.Set(identity, dataFileLength); AutoCSer.DomainUnload.Unloader.Add(disposeHandle, DomainUnload.Type.Action); isDisposed = 0; } finally { buffer.TryFree(); if (isDisposed == 0) { Interlocked.Exchange(ref isWrite, 0); onStart(); if (!bufferQueue.IsEmpty && Interlocked.CompareExchange(ref isWrite, 1, 0) == 0) { write(); } } else { indexs.Length = 0; Dispose(); } } }
/// <summary> /// 压缩数据 /// </summary> /// <param name="isFastestCompressionLevel"></param> internal void Compress(bool isFastestCompressionLevel) #endif { switch (Type) { case Net.Http.ResponseType.ByteArray: Body.SetFull(); goto SUBBYTEARRAY; case Net.Http.ResponseType.SubByteArray: SUBBYTEARRAY: if (Body.Length > GZipHeaderSize + 256) { SubArray <byte> compressData = default(SubArray <byte>); try { #if DOTNET2 || DOTNET4 if (AutoCSer.IO.Compression.GzipCompressor.Get(Body.Array, Body.Start, Body.Length, ref SubBuffer, ref compressData, 0, GZipHeaderSize)) #else if (AutoCSer.IO.Compression.GzipCompressor.Get(Body.Array, Body.Start, Body.Length, ref SubBuffer, ref compressData, 0, GZipHeaderSize, isFastestCompressionLevel)) #endif { Body = compressData; Type = compressData.Array == SubBuffer.Buffer ? ResponseType.SubBuffer : ResponseType.SubByteArray; ContentEncoding = GZipEncoding; Flag |= ResponseFlag.ContentEncoding; } } finally { if (Type != ResponseType.SubBuffer) { SubBuffer.Free(); } } } return; case Net.Http.ResponseType.SubBuffer: if (Body.Length > GZipHeaderSize + 256) { SubBuffer.PoolBufferFull compressBuffer = default(SubBuffer.PoolBufferFull); SubArray <byte> compressData = default(SubArray <byte>); byte isCompress = 0; try { #if DOTNET2 || DOTNET4 if (AutoCSer.IO.Compression.GzipCompressor.Get(Body.Array, Body.Start, Body.Length, ref compressBuffer, ref compressData, 0, GZipHeaderSize)) #else if (AutoCSer.IO.Compression.GzipCompressor.Get(Body.Array, Body.Start, Body.Length, ref compressBuffer, ref compressData, 0, GZipHeaderSize, isFastestCompressionLevel)) #endif { isCompress = 1; SubBuffer.Free(); Body = compressData; if (compressData.Array == compressBuffer.Buffer) { SubBuffer = compressBuffer; } else { Type = ResponseType.SubByteArray; } ContentEncoding = GZipEncoding; Flag |= ResponseFlag.ContentEncoding; } } finally { if (isCompress == 0 || Type != ResponseType.SubBuffer) { compressBuffer.Free(); } } } return; } }