www.pudn.com > using IOCP.zip > client.cpp
#define _WIN32_WINNT 0x0500 #include#include "client.h" #include "buffer.h" #include "general.h" extern SOCKET listener; CClient::CClient() { out_buffer = new CAutoBuffer(BASE_BUFFER_INC); actual_in_buf = new char [IN_BUFFER_SIZE]; actual_out_buf = new char [OUT_BUF_SIZE]; nInBufferSize = IN_BUFFER_SIZE; ovOut.Internal = 0; ovOut.InternalHigh = 0; ovOut.Offset = 0; ovOut.OffsetHigh = 0; ovIn.Internal = 0; ovIn.InternalHigh = 0; ovIn.Offset = 0; ovIn.OffsetHigh = 0; ovOut.hEvent = NULL; ovIn.hEvent = NULL; ovOut.client = (unsigned int)this; ovIn.client = (unsigned int)this; ovOut.bCtxWrite = true; ovIn.bCtxWrite = false; ovOut.bIsTCP = true; ovIn.bIsTCP = true; this->nState = STATE_DEAD; p = new tagPacket(); InitializeInUse(); nSpecificID = nID++; } CClient::~CClient() { if (out_buffer) delete out_buffer; if (actual_in_buf) delete [] actual_in_buf; if (actual_out_buf) delete [] actual_out_buf; if (p) delete p; end_in_buf_pos = NULL; start_in_buf_pos = NULL; DeleteInUse(); } void CClient::Init() { bMayWrite = 1; bPendingWrite = 0; end_in_buf_pos = actual_in_buf; start_in_buf_pos = actual_in_buf; s = socket(AF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { // Problem. this->nState = STATE_DEAD; return; } if (!AcceptEx(listener, s, &actual_in_buf[0], IN_BUFFER_SIZE, sizeof(sockaddr_in) + 16, sizeof(sockaddr_in) + 16, &nRead, &ovIn)) { if (GetLastError() != ERROR_IO_PENDING) { // Problem. this->nState = STATE_DEAD; closesocket(s); return; } } this->nState = STATE_ACCEPTING; } void CClient::Close() { if (nState != STATE_DEAD) { if (nState == STATE_CONNECTED) { struct linger li = {0, 0}; // Default: SO_DONTLINGER shutdown(s, SD_BOTH); setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&li, sizeof(li)); } closesocket(s); this->nState = STATE_DEAD; } } bool CClient::Write(tagPacket *p) { // Add to output buffer. // If no write is currently being performed, we can simply copy the data // to actual_out_buf. However - if actual_out_buf is currently being // touched, we need to store the buffer in out_buffer first. EnterInUse(); if (bMayWrite) { InterlockedDecrement(&bMayWrite); // First, make sure that we can send the whole buffer at once. If we // can't, we will do it through the out_buffer class. if (OUT_BUF_SIZE >= p->nLength - 4) { // It's ok, let's do it! memcpy(actual_out_buf, &p->nLength, 4); memcpy(actual_out_buf + 4, p->buffer, p->nLength); WriteFile((HANDLE)s, actual_out_buf, p->nLength + 4, &nWritten, &ovOut); } else { // Ok, the buffer is too large to be contained in // actual_out_buffer, so let's do this in phases, using // out_buffer. out_buffer->AddToBuffer((char *)&p->nLength, 4); if (p->nLength > 0) out_buffer->AddToBuffer(p->buffer, p->nLength); bPendingWrite = 1; NetWrite(); } } else { // A send is currently underway. // Do it through actual_out_buffer. out_buffer->AddToBuffer((char *)&p->nLength, 4); if (p->nLength > 0) out_buffer->AddToBuffer(p->buffer, p->nLength); bPendingWrite = 1; } LeaveInUse(); /* The EnterInUse() and LeaveInUse() functions are needed so there won't be a race condition, when two threads are calling this function for the same client simultaneously. If, however, because of the nature of your application, such thing cannot happen, you can override those functions to do nothing, in order to improve performance. */ return true; } void CClient::SetRead(int nNewlyRead) { Timestamp(); nRead = nNewlyRead; end_in_buf_pos += nRead; } bool CClient::Read(tagPacket *p) { int nContents; int nTemp; int nTempContents; bool bRet = false; char *newbuf; bool bAnother = false; // Start looking at start_in_buf_pos. // Buffer ends at end_in_buf_pos. // Total buffer size is nInBufferSize // Currently, only nInBufferSize - (end_in_buf_pos - actual_in_buf) // bytes are available, starting at end_in_buf_pos. // First, let's see that we have available 4 bytes. nContents = end_in_buf_pos - start_in_buf_pos; if (nContents >= 4) { // Let's see if we have a complete packet. memcpy(&nTemp, start_in_buf_pos, 4); if (nTemp > p->nSize) { p->nSize = nTemp; if (p->buffer) delete [] p->buffer; p->buffer = new char [p->nSize]; } p->nLength = nTemp; if (nContents >= p->nLength + 4) { // There is a complete packet memcpy(p->buffer, start_in_buf_pos + 4, p->nLength); // See if we can reset the pointers start_in_buf_pos += p->nLength + 4; if (start_in_buf_pos == end_in_buf_pos) { // Reset pointers start_in_buf_pos = end_in_buf_pos = actual_in_buf; } bRet = true; } else { // There isn't a complete packet bRet = false; } } else { // Not enough data has arrived. bRet = false; } // Let's see if there is another packet pending. nTempContents = end_in_buf_pos - start_in_buf_pos; if (bRet) { if (end_in_buf_pos - start_in_buf_pos >= 4) { memcpy(&nTemp, start_in_buf_pos, 4); if (nTemp <= nTempContents - 4) bAnother = true; } } if (!bAnother) { // There isn't another packet pending - do the moves now. // Now, let's see if there is enough room for more data to enter. if (end_in_buf_pos - actual_in_buf >= nInBufferSize) { // There is not enough room for more data. // Check to see if we can move the contents of the buffer backwards. if (start_in_buf_pos > actual_in_buf) { // Yes, we can move contents memmove(actual_in_buf, start_in_buf_pos, nTempContents); start_in_buf_pos = actual_in_buf; end_in_buf_pos = actual_in_buf + nTempContents; } else { // We can't move. Need to expand the buffer. // Make sure that we are allowed to expand the buffer. if (nInBufferSize < MAX_IN_BUFFER_SIZE) { // We may expand the buffer. newbuf = new char [nInBufferSize + IN_BUFFER_SIZE_INC]; memcpy(newbuf, actual_in_buf, nInBufferSize); delete [] actual_in_buf; actual_in_buf = start_in_buf_pos = newbuf; end_in_buf_pos = actual_in_buf + nInBufferSize; nInBufferSize += IN_BUFFER_SIZE_INC; } else { // We cannot expand the buffer - maximum size was reached. // This is seriously bad. Give inhereted classes a chance // to modify the packet as they wish, and return. CreateInvalidPacket(p); bRet = true; // In order to allow processing // of this packet. } } } } return bRet; } bool CClient::NetWrite() { int nLength; nLength = OUT_BUF_SIZE; out_buffer->GetBuffer(actual_out_buf, &nLength); if (out_buffer->IsEmpty()) { bPendingWrite = 0; } else { bPendingWrite = 1; } nWritten = 0; bMayWrite = 0; // Can't do further writes, it's underway! WriteFile((HANDLE)s, actual_out_buf, nLength, &nWritten, &ovOut); return true; } bool CClient::IssueNetRead() { nRead = 0; int nLastError; int nCount; if (nState == STATE_CONNECTED) { nCount = nInBufferSize - (end_in_buf_pos - actual_in_buf); memset((char *)&ovIn, 0, sizeof(OVERLAPPED)); if (0 == ReadFile((HANDLE)s, end_in_buf_pos, nCount, &nRead, &ovIn)) { nLastError = GetLastError(); if (ERROR_IO_PENDING != nLastError) printf("\nError occured while calling ReadFile(..): %d", nLastError); } return true; } else return false; }