Win network programming-iocp Service Program-(2)

Source: Internet
Author: User

 


Bool ciocpserver: addaconnection (ciocpcontext * pcontext)
{
// Add a ciocpcontext object to the client connection list

: Entercriticalsection (& m_connectionlistlock );
If (m_ncurrentconnection <= m_nmaxconnections)
{
// Add to the header
Pcontext-> pnext = m_pconnectionlist;
M_pconnectionlist = pcontext;
// Update count
M_ncurrentconnection ++;

: Leavecriticalsection (& m_connectionlistlock );
Return true;
}
: Leavecriticalsection (& m_connectionlistlock );

Return false;
}

Void ciocpserver: closeaconnection (ciocpcontext * pcontext)
{
// First remove the connection to be closed from the list
: Entercriticalsection (& m_connectionlistlock );

Ciocpcontext * Ptest = m_pconnectionlist;
If (Ptest = pcontext)
{
M_pconnectionlist = pcontext-> pnext;
M_ncurrentconnection --;
}
Else
{
While (Ptest! = NULL & Ptest-> pnext! = Pcontext)
Ptest = Ptest-> pnext;
If (Ptest! = NULL)
{
Ptest-> pnext = pcontext-> pnext;
M_ncurrentconnection --;
}
}
 
: Leavecriticalsection (& m_connectionlistlock );

// Close the customer's Character Set
: Entercriticalsection (& pcontext-> lock );

If (pcontext-> S! = Invalid_socket)
{
: Closesocket (pcontext-> S );
Pcontext-> S = invalid_socket;
}
Pcontext-> bclosing = true;

: Leavecriticalsection (& pcontext-> lock );
}

Void ciocpserver: closeallconnections ()
{
// Traverse the entire connection list and close all customer Sets

: Entercriticalsection (& m_connectionlistlock );

Ciocpcontext * pcontext = m_pconnectionlist;
While (pcontext! = NULL)
{
: Entercriticalsection (& pcontext-> lock );

If (pcontext-> S! = Invalid_socket)
{
: Closesocket (pcontext-> S );
Pcontext-> S = invalid_socket;
}

Pcontext-> bclosing = true;

: Leavecriticalsection (& pcontext-> lock );
 
Pcontext = pcontext-> pnext;
}

M_pconnectionlist = NULL;
M_ncurrentconnection = 0;

: Leavecriticalsection (& m_connectionlistlock );
}

Bool ciocpserver: insertpendingaccept (ciocpbuffer * pbuffer)
{

// M_ppendingaccepts table is a pending accept request, which is formed by the ciocpbuffer buffer object during the request.
// Insert an I/O buffer object to the m_ppendingaccepts table

: Entercriticalsection (& m_pendingacceptslock );

If (m_ppendingaccepts = NULL)
M_ppendingaccepts = pbuffer;
Else
{
Pbuffer-> pnext = m_ppendingaccepts;
M_ppendingaccepts = pbuffer;
}
M_npendingacceptcount ++;

: Leavecriticalsection (& m_pendingacceptslock );

Return true;
}

Bool ciocpserver: removependingaccept (ciocpbuffer * pbuffer)
{
Bool bresult = false;

// Traverse the m_ppendingaccepts table and remove the buffer object pointed to by pbuffer.
: Entercriticalsection (& m_pendingacceptslock );

Ciocpbuffer * Ptest = m_ppendingaccepts;
If (Ptest = pbuffer) // if it is a header Element
{
M_ppendingaccepts = pbuffer-> pnext;
Bresult = true;
}
Else // if it is not a Header element, You need to traverse the table to find it.
{
While (Ptest! = NULL & Ptest-> pnext! = Pbuffer)
Ptest = Ptest-> pnext;
If (Ptest! = NULL)
{
Ptest-> pnext = pbuffer-> pnext;
Bresult = true;
}
}
// Update count
If (bresult)
M_npendingacceptcount --;

: Leavecriticalsection (& m_pendingacceptslock );

Return bresult;
}

Ciocpbuffer * ciocpserver: getnextreadbuffer (ciocpcontext * pcontext, ciocpbuffer * pbuffer)
{

// Because the I/O completion port may cause unordered packet transfer, a serial number is added to the buffer.
If (pbuffer! = NULL)
{
// If it is equal to the next serial number to be read, read this buffer
If (pbuffer-> nsequencenumber = pcontext-> ncurrentreadsequence)
{
Return pbuffer;
}
 
// If they are not equal, the data is not received in order. Save the buffer to the connected poutoforderreads list.

// The buffer in the list is arranged in ascending order of its serial number

Pbuffer-> pnext = NULL;
 
Ciocpbuffer * PTR = pcontext-> poutoforderreads;
Ciocpbuffer * PPRE = NULL;
While (PTR! = NULL)
{
If (pbuffer-> nsequencenumber <PTR-> nsequencenumber)
Break;

PPRE = PTR;
PTR = PTR-> pnext;
}
 
If (PPRE = NULL) // insert to the header
{
Pbuffer-> pnext = pcontext-> poutoforderreads;
Pcontext-> poutoforderreads = pbuffer;
}
Else // It should be inserted in the middle of the table
{
Pbuffer-> pnext = PPRE-> pnext;
PPRE-> pnext = pbuffer-> pnext;
}
}

// Check the serial number of the table Header element. If it is consistent with the serial number to be read, remove it from the table and return it to the user.
Ciocpbuffer * PTR = pcontext-> poutoforderreads;
If (PTR! = NULL & (PTR-> nsequencenumber = pcontext-> ncurrentreadsequence ))
{
Pcontext-> poutoforderreads = PTR-> pnext;
Return PTR;
}
Return NULL;
}

Bool ciocpserver: postaccept (ciocpbuffer * pbuffer) // deliver the accept request on the listening set of characters
{
// Set the I/O type
Pbuffer-> noperation = op_accept;

// Deliver this overlapping I/O
DWORD dwbytes;
Pbuffer-> sclient =: wsasocket (af_inet, sock_stream, 0, null, 0, wsa_flag_overlapped );
Bool B = m_lpfnacceptex (m_slisten,
Pbuffer-> sclient,
Pbuffer-> buff,
Pbuffer-> nlen-(sizeof (sockaddr_in) + 16) * 2 ),
Sizeof (sockaddr_in) + 16,
Sizeof (sockaddr_in) + 16,
& Dwbytes,
& Pbuffer-> ol );
If (! B &: wsagetlasterror ()! = Wsa_io_pending)
{
Return false;
}
Return true;
};

Bool ciocpserver: postrecv (ciocpcontext * pcontext, ciocpbuffer * pbuffer)
{
// Set the I/O type
Pbuffer-> noperation = op_read;
 
: Entercriticalsection (& pcontext-> lock );

// Set the serial number
Pbuffer-> nsequencenumber = pcontext-> nreadsequence;

// Deliver this overlapping I/O
DWORD dwbytes;
DWORD dwflags = 0;
Wsabuf Buf;
Buf. Buf = pbuffer-> Buff;
Buf. Len = pbuffer-> nlen;
If (: wsarecv (pcontext-> S, & Buf, 1, & dwbytes, & dwflags, & pbuffer-> ol, null )! = No_error)
{
If (: wsagetlasterror ()! = Wsa_io_pending)
{
: Leavecriticalsection (& pcontext-> lock );
Return false;
}
}

// Add overlapping I/O count and read serial number count on the set of characters

Pcontext-> noutstandingrecv ++;
Pcontext-> nreadsequence ++;

: Leavecriticalsection (& pcontext-> lock );

Return true;
}

Bool ciocpserver: postsend (ciocpcontext * pcontext, ciocpbuffer * pbuffer)
{
// Track the number of deliveries to prevent the server from throwing out a large number of sending operations because the server only sends data but does not receive it.
If (pcontext-> noutstandingsend> m_nmaxsends)
Return false;

// Set the I/O type and add the overlapping I/O count on the set words
Pbuffer-> noperation = op_write;

// Deliver this overlapping I/O
DWORD dwbytes;
DWORD dwflags = 0;
Wsabuf Buf;
Buf. Buf = pbuffer-> Buff;
Buf. Len = pbuffer-> nlen;
If (: wsasend (pcontext-> S,
& Buf, 1, & dwbytes, dwflags, & pbuffer-> ol, null )! = No_error)
{
If (: wsagetlasterror ()! = Wsa_io_pending)
Return false;
}
 
// Add the overlapping I/O count on the set of characters
: Entercriticalsection (& pcontext-> lock );
Pcontext-> noutstandingsend ++;
: Leavecriticalsection (& pcontext-> lock );

Return true;
}

Bool ciocpserver: Start (INT nport, int nmaxconnections,
Int nmaxfreebuffers, int nmaxfreecontexts, int ninitialreads)
{
// Check whether the service has been started
If (m_bserverstarted)
Return false;

// Save USER Parameters
M_nport = nport;
M_nmaxconnections = nmaxconnections;
M_nmaxfreebuffers = nmaxfreebuffers;
M_nmaxfreecontexts = nmaxfreecontexts;
M_ninitialreads = ninitialreads;

// Initialize the status variable
M_bshutdown = false;
M_bserverstarted = true;

// Create a listening set, bind it to the local port, and enter the listening mode
M_slisten =: wsasocket (af_inet, sock_stream, 0, null, 0, wsa_flag_overlapped );
Sockaddr_in Si;
Si. sin_family = af_inet;
Si. sin_port =: ntohs (m_nport );
Si. sin_addr.s_un.s_addr = inaddr_any;
If (: BIND (m_slisten, (sockaddr *) & Si, sizeof (SI) = socket_error)
{
M_bserverstarted = false;
Return false;
}
: Listen (m_slisten, 200 );

// Create a port object
M_hcompletion =: createiocompletionport (invalid_handle_value, 0, 0, 0 );

// Load the Extended Function acceptex
Guid guidacceptex = wsaid_acceptex;
DWORD dwbytes;
: Wsaioctl (m_slisten,
Sio_get_extension_function_pointer,
& Guidacceptex,
Sizeof (guidacceptex ),
& M_lpfnacceptex,
Sizeof (m_lpfnacceptex ),
& Dwbytes,
Null,
Null );
 
// Load the Extended Function getacceptexsockaddrs
Guid guidgetacceptexsockaddrs = wsaid_getacceptexsockaddrs;
: Wsaioctl (m_slisten,
Sio_get_extension_function_pointer,
& Guidgetacceptexsockaddrs,
Sizeof (guidgetacceptexsockaddrs ),
& M_lpfngetacceptexsockaddrs,
Sizeof (m_lpfngetacceptexsockaddrs ),
& Dwbytes,
Null,
Null
);
 
 
// Associate the listening set with the completion port. Note that the completionkey passed here is 0.
: Createiocompletionport (handle) m_slisten, m_hcompletion, (DWORD) 0, 0 );

// Register the fd_accept event.
// If the delivery acceptex I/O is insufficient, the thread will receive the fd_accept network event, indicating that more acceptex I/O should be shipped.
Wsaeventselect (m_slisten, m_hacceptevent, fd_accept );

// Create a listening thread
M_hlistenthread =: createthread (null, 0, _ listenthreadproc, this, 0, null );
 
Return true;
}

Void ciocpserver: Shutdown ()
{
If (! M_bserverstarted)
Return;

// Notify the listening thread to stop the service immediately
M_bshutdown = true;
: Setevent (m_hacceptevent );
// Wait for the listening thread to exit
: Waitforsingleobject (m_hlistenthread, infinite );
: Closehandle (m_hlistenthread );
M_hlistenthread = NULL;

M_bserverstarted = false;
}

DWORD winapi ciocpserver: _ listenthreadproc (lpvoid lpparam)
{
Ciocpserver * pthis = (ciocpserver *) lpparam;

// First deliver several accept I/O packets on the listening set.
Ciocpbuffer * pbuffer;
For (INT I = 0; im_ninitialaccepts; I ++)
{
Pbuffer = pthis-> allocatebuffer (buffer_size );
If (pbuffer = NULL)
Return-1;
Pthis-> insertpendingaccept (pbuffer );
Pthis-> postaccept (pbuffer );
}

// Construct an array of event objects to call the wsawaitformultipleevents Function
Handle hwaitevents [2 + max_thread];
Int neventcount = 0;
Hwaitevents [neventcount ++] = pthis-> m_hacceptevent;
Hwaitevents [neventcount ++] = pthis-> m_hrepostevent;

// Create a specified number of worker threads to process I/O on the finished Port
For (I = 0; I
{
Hwaitevents [neventcount ++] =: createthread (null, 0, _ workerthreadproc, pthis, 0, null );
}

// Enter an infinite loop below to process events in the event object Array
While (true)
{
Int nindex =: wsawaitformultipleevents (neventcount, hwaitevents, false, 60*1000, false );
 
// First check whether the service is to be stopped
If (pthis-> m_bshutdown | nindex = wsa_wait_failed)
{
// Close all connections
Pthis-> closeallconnections ();
: Sleep (0); // give the I/O worker thread a chance to execute
// Disable the listening unit.
: Closesocket (pthis-> m_slisten );
Pthis-> m_slisten = invalid_socket;
: Sleep (0); // give the I/O worker thread a chance to execute

// Notify all I/O processing threads to exit
For (INT I = 2; I
{
: Postqueuedcompletionstatus (pthis-> m_hcompletion,-1, 0, null );
}

// Wait for the I/O processing thread to exit
: Waitformultipleobjects (max_thread, & hwaitevents [2], true, 5*1000 );

For (I = 2; I
{
: Closehandle (hwaitevents [I]);
}
 
: Closehandle (pthis-> m_hcompletion );

Pthis-> freebuffers ();
Pthis-> freecontexts ();
: Exitthread (0 );
}

// 1) regularly check how long the connections for all unreturned acceptex I/O have been established
If (nindex = wsa_wait_timeout)
{
Pbuffer = pthis-> m_ppendingaccepts;
While (pbuffer! = NULL)
{
Int nseconds;
Int nlen = sizeof (nseconds );
// Obtain the connection establishment time
: Getsockopt (pbuffer-> sclient,
Sol_socket, so_connect_time, (char *) & nseconds, & nlen );
// If the customer does not send the initial data for more than 2 minutes, let the customer go away
If (nseconds! =-1 & nseconds> 2*60)
{
Closesocket (pbuffer-> sclient );
Pbuffer-> sclient = invalid_socket;
}

Pbuffer = pbuffer-> pnext;
}
}
Else
{
Nindex = nindex-wait_object_0;
Wsanetworkevents ne;
Int nlimit = 0;
If (nindex = 0) // 2) m_hacceptevent event object received, it indicates that the shipping accept request is insufficient and you need to add
{
: Wsaenumnetworkevents (pthis-> m_slisten, hwaitevents [nindex], & ne );
If (ne. lnetworkevents & fd_accept)
{
Nlimit = 50; // increase the number. Set this parameter to 50.
}
}
Else if (nindex = 1) // 3) m_hrepostevent event object received, indicating that the thread processing I/O received the new customer
{
Nlimit = interlockedexchange (& pthis-> m_nrepostcount, 0 );
}
Else if (nindex> 1) // the I/O service thread exits, indicating an error occurred. Disable the server.
{
Pthis-> m_bshutdown = true;
Continue;
}

// Deliver nlimit acceptex I/O requests
Int I = 0;
While (I ++ <nlimit & pthis-> m_npendingacceptcount <pthis-> m_nmaxaccepts)
{
Pbuffer = pthis-> allocatebuffer (buffer_size );
If (pbuffer! = NULL)
{
Pthis-> insertpendingaccept (pbuffer );
Pthis-> postaccept (pbuffer );
}
}
}
}
Return 0;
}

DWORD winapi ciocpserver: _ workerthreadproc (lpvoid lpparam)
{
# Ifdef _ debug
: Outputdebugstring ("workerthread startup.../N ");
# Endif // _ debug

Ciocpserver * pthis = (ciocpserver *) lpparam;

Ciocpbuffer * pbuffer;
DWORD dwkey;
DWORD dwtrans;
Lpoverlapped lpol;
While (true)
{
// Wait for I/O to be completed on all the characters associated with this port.
Bool Bok =: getqueuedcompletionstatus (pthis-> m_hcompletion,
& Dwtrans, (lpdword) & dwkey, (lpoverlapped *) & lpol, wsa_infinite );

If (dwtrans =-1) // user notification exits
{
# Ifdef _ debug
: Outputdebugstring ("workerthread logout/N ");
# Endif // _ debug
: Exitthread (0 );
}

Pbuffer = containing_record (lpol, ciocpbuffer, Ol );
Int nerror = no_error;
If (! Bok) // an error occurs in this set of characters.
{
Socket S;
If (pbuffer-> noperation = op_accept)
{
S = pthis-> m_slisten;
}
Else
{
If (dwkey = 0)
Break;
S = (ciocpcontext *) dwkey)-> S;
}
DWORD dwflags = 0;
If (! : Wsagetoverlappedresult (S, & pbuffer-> ol, & dwtrans, false, & dwflags ))
{
Nerror =: wsagetlasterror ();
}
}
Pthis-> handleio (dwkey, pbuffer, dwtrans, nerror );
}

# Ifdef _ debug
: Outputdebugstring ("workerthread logout/N ");
# Endif // _ debug
Return 0;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.