Http://blog.csdn.net/hulihui/article/details/3260685
(Original article, reproduced please indicate the source: http://blog.csdn.net/hulihui)
In the receiving/sending methods of socket: Send (), beginsend (), receive (), and beginreceive (), the first parameter is the number of bytes.
Group, indicating the current receiving data area or the data to be sent. In common socket applications, an array is usually created when an array is received/sent. After the array space is used, it is recycled by the managed heap (the array space is associated after the socket is closed ).
). Obviously, frequent creation of the receiving/sending buffer leaves a lot of memory fragments on the hosting stack, affecting system performance.
When using Socket asynchronous event parameter class socketasynceventargs, the above situation is taken into account. The basic idea is: to customize a buffer management class, such as buffermanager, to open up a large, reusable receiving/sending and receiving buffer, used for sendasync (), receiveasync (), and other methods. Previously, setbuffer () and attribute offset and count were used to set the buffer space.
In fact, this technology is still available in the traditional socket APM (asynchronous programming model) on the. NET 2.0 platform. The modified buffermanager class is as follows:
Public sealed class buffermanager
{
//... All fields are private. For the type and name, see the constructor.
Public buffermanager (INT maxsessioncount, int distinct evbuffersize, int sendbuffersize)
{
M_maxsessioncount = maxsessioncount; // maximum number of accessible clients, int
M_receivebuffersize = incluevbuffersize; // the size of the receiving buffer, int
M_sendbuffersize = sendbuffersize; // int
M_bufferblockindex = 0; // The Index Number of the currently unused buffer block, int
M_bufferblockindexstack = new stack (); // The Index Number of the buffer block that can be reused. Stack <int> generic
M_receivebuffer = new byte [m_receivebuffersize * m_maxsessioncount]; // size of the receiving buffer
M_sendbuffer = new byte [m_sendbuffersize * m_maxsessioncount];
}
Public int receivebuffersize
{
Get {return m_receivebuffersize ;}
}
Public int sendbuffersize
{
Get {return m_sendbuffersize ;}
}
Public byte [] receivebuffer
{
Get {return m_receivebuffer ;}
}
Public byte [] sendbuffer
{
Get {return m_sendbuffer ;}
}
Public void freebufferblockindex (INT bufferblockindex) // reclaim the block Index Number
{
If (bufferblockindex =-1)
{
Return;
}
Lock (this)
{
M_bufferblockindexstack.push (bufferblockindex );
}
}
Public int getbufferblockindex () // obtain the index number of the available buffer Block
{
Lock (this)
{
Int blockindex =-1;
If (m_bufferblockindexstack.count> 0) // a buffer block that has been released
{
Blockindex = m_bufferblockindexstack.pop ();
}
Else
{
If (m_bufferblockindex <m_maxsessioncount) // There are unused buffer Blocks
{
Blockindex = m_bufferblockindex ++;
}
}
Return blockindex;
}
}
Public int getincluevbufferoffset (INT bufferblockindex)
{
If (bufferblockindex =-1) // shared block is not used
{
Return 0; // indicates creating a buffer. The offset is 0.
}
Return bufferblockindex * m_receivebuffersize; // the offset of the receiving block (array start subscript)
}
Public int getsendbufferoffset (INT bufferblockindex)
{
If (bufferblockindex =-1) // shared block is not used
{
Return 0;
}
Return bufferblockindex * m_sendbuffersize; // sending block offset (array start subscript)
}
Public void clear ()
{
Lock (this)
{
M_bufferblockindexstack.clear ();
M_receivebuffer = NULL;
M_sendbuffer = NULL;
}
}
}
In the above Code, m_maxsessioncount is the maximum number of client sockets that can be connected to the socket server. The buffermanager constructor requires this number and the size of the buffer for receiving and sending, to create two large, reusable shared buffers.
The procedure is as follows:
- Create a buffermanager object m_buffermanager
- Obtain the index number of the buffer block: m_bufferblockindex = m_buffermanager.getbufferblockindex ()
- Asynchronous receiving: Calculate the buffer offset address and then start receiving
- Asynchronous sending: first consider the length of the sending string and then decide whether to use the Buffer Zone. For details, refer to the subsequent code.
- If no block index number is used, m_buffermanager.freebufferblockindext (m_bufferblockindex) is recycled.
The following is an example code for applying for a Buffer Index Number:
M_bufferblockindex = buffermanager. getbufferblockindex ();
If (m_bufferblockindex =-1) // no empty block, new receiving/sending Buffer
{
M_receivebuffer = new byte [m_buffermanager.receivebuffersize];
M_sendbuffer = new byte [m_buffermanager.sendbuffersize];
}
Else // empty buffer block, which is directly referenced
{
M_receivebuffer = m_buffermanager.receivebuffer;
M_sendbuffer = m_buffermanager.sendbuffer;
}
The following is a sample code for receiving data asynchronously from a socket:
Int bufferoffset = m_buffermanager.get1_evbufferoffset (m_bufferblockindex); // calculate the start address
M_socket.beginreceive (m_receivebuffer, bufferoffset, m_buffermanager.receivebuffersize,
Socketflags. None, this. endreceivedat.pdf, this );
The following is an example of code for sending the string mongoramtext asynchronously through socket:
Int bytelength = encoding. ASCII. getbytecount (datagramtext );
If (bytelength <= m_buffermanager.sendbuffersize) // you can use the shared buffer.
{
Int bufferoffset = m_buffermanager.getsendbufferoffset (m_bufferblockindex); // calculates the start address.
Encoding. ASCII. getbytes (datagramtext, 0, bytelength, m_sendbuffer, bufferoffset );
M_socket.beginsend (m_sendbuffer, bufferoffset, bytelength, socketflags. None,
This. endsenddatagram, this );
}
Else // The Shared Buffer cannot be used.
{
Byte [] DATA = encoding. ASCII. getbytes (datagramtext); // obtain the Data byte array
M_socket.beginsend (data, 0, Data. length, socketflags. None, this. endsenddatagram, this );
}
When sending data, if the size of the sending buffer is greater than the size of the actually sent package, the buffermanager public buffer can be used for asynchronous sending. Otherwise, a new sending buffer (Word
Array ). In addition, using the shared buffer to send long data packets multiple times is also an option that can be considered, but the implementation is complicated (to be solved later ). Receive data directly
Buffermanager, because long data packets are automatically received multiple times by the socket, the packet receiving sequence and other issues do not need to be considered. Another thing to note is that the obtained Buffer Index block number
Remember to recycle them.
The performance improvement of event-driven socketasynceventargs is not only related to the technology that uses the shared buffer, but also shared with the completed port (iocp ).
Socketasynceventargs object, which can be reused. In traditional asynchronous socket processing, an iasyncresult object is always created,
This object cannot be used repeatedly and must call asyncwaithandle. Close () to release resources. Obviously, the shared buffer technology only slightly improves the performance of the application system.
To eliminate the APM defects of the socket.
The preceding buffer class provides a technical solution for receiving/sending buffer that can be reused by a socket, for specific implementation, see Introduction and source code Resources in the extended multi-threaded asynchronous socket server framework emtass 2.0 and Version 2.1.