본문 바로가기

old_Coding/WinSocket

Circular Buffer (Ring Buffer) (*)




For the first step to implement an IOCP(Input/Output Completion Port) server model, I simply made a buffer interface to use in the server. I used a buffer which I called "pulled buffer". I'm going to show you my new Ring Buffer with the pulled buffer.


* Pulled Buffer *
I'd used this pulled buffer for blocking-server models. Its principle is very simple.
You can easily understand this. It's assumed to use packets which contains information, (Size+Header) + (Data).

Hypothesize that a 8 bytes pulled buffer(Of course, it should be larger than 8 bytes in real situations)

|  |  |  |  |  |  |  |  |
  0  1  2  3  4  5  6  7

When I receive data, "abc", the buffer would be changed like this.
|a|b|c|  |  |  |  |  |
and I have a message, "xyz", again from the same computer. Then the message will be pushed back.
|a|b|c|x|y|z|  |  |

I have to order to computer to process, and the processed data will be removed, because its size is limited as 8 bytes. To process the packet, I take out "abcx". With this steps, the buffer will be change.
|y|z|  |  |  |  |  |  |

I receive again the packet, "Apple"
|y|z|A|p|p|l|e|  |

During the processing, it's necessary to copy 'yz' to be pulled from the 4th index to the zero index. It's cause to make overhead, so I changed to the Ring Buffer.



* Ring Buffer *
Assume the same situation that I showed. The difference is Ring Buffer has two index (or pointer).
Processing Start Pointer(PS), Writing Start Pointer(WS)  <--- I named it.

|  |  |  |  |  |  |  |  | PS = 0, WS = 0
  0  1  2  3  4  5  6  7

With receiving "abc",
|a|b|c|  |  |  |  |  | PS = 0, WS = 3
and adding "xyz"
|a|b|c|x|y|z|  |  | PS = 0, WS = 6

I order to the computer to process the message, "abcx". Then we can simply change the PS(Processing Start Pointer).
|a|b|c|x|y|z|  |  | PS = 4, WS = 6

And receiving "Apple",
|p|l|e|  |y|z|A|p| PS = 4, WS = 3

It has no copy time, because the messages will be written on current spot according to the PS & WS. However you should be careful about size. Ring Buffer requires large size than the packet size that can be received one time.


* Implementation *

I made it, using C++ language and Microsoft Visual Studio 2008.
"RingContext.h"

const int BUFFER_SIZE = 16 ;
class cRingContext
{
private :
// Data structure
char m_Buffer[BUFFER_SIZE] ;
int m_Bytes ;
int m_ProcessingStart ;
int m_WritingStart ;
bool m_IsLink ;

// Hiding functions
void _MoveProcessingStart(int __in _index) ;
void _MoveWritingStart(int __in _index) ;
void _ResetProcessingStart() ;
void _ResetWritingStart() ;
void _AddBytes(int __in _Add) ;
int _SetByte(int __in _Bytes) ;
void _CheckIsLink() ;
int _Write(char* __in _Ptr, int __in _Bytes ) ;
int _Read(char* __out _New, int __in _Bytes ) ;
public:
cRingContext(void);
~cRingContext(void);
bool Reset() ;
bool RePlace() ;
// with copy (block)
int WriteToBuffer(char* __in _Ptr, int __in _Bytes)  ;
int ReadFromBuffer(char* __out _Ptr, int __out&_Bytes ) ;
int ObserveBuffer(char* __out _Ptr, int __out &_Bytes) ;
// without copy (non-block)
char* MoveProcessingStart(int __in _Bytes) ;
char* MoveWritingStart(int __in _Bytes) ;
// Get, Set functions
char* GetProcessingPtr() ;
char* GetWritingPtr()  ;
bool GetIsLink() ;
int GetProcessingLength() ; // From ProcessingStart To WritingStart
int GetWritingLength() ; // from WritingStart To BUFFER_SIZE
void Output() ;
};



I contain the files with header & source too, but I haven't finish to implement the server yet, so it will be changed in many parts. Please understand about it.





- ps.
This blog is for my English abilities, and I'm not good at communicating in English. If you see grammatic, syntax or logical errors, or if you can't understand clearly, PLEASE COMMENT ON IT. Your comments definitely help me, and I really appreciate this. :)

- Written by Gordon