blockSock.cpp&ClientInerThread

// blocksock.cpp (CBlockingSocketException, CBlockingSocket, CHttpBlockingSocket)
#include <stdafx.h>
#include "blocksock.h"

// Class CBlockingSocketException
IMPLEMENT_DYNAMIC(CBlockingSocketException, CException)

CBlockingSocketException::CBlockingSocketException(char* pchMessage)
{
 m_strMessage = pchMessage;
 m_nError = WSAGetLastError();
}

BOOL CBlockingSocketException::GetErrorMessage(LPTSTR lpstrError, UINT nMaxError,
  PUINT pnHelpContext /*= NULL*/)
{

 char text[200];
 if(m_nError == 0) {
  wsprintf(text, "%s error", (const char*) m_strMessage);
 }
 else {
  wsprintf(text, "%s error #%d", (const char*) m_strMessage, m_nError);
 }
 strncpy(lpstrError, text, nMaxError - 1);
 return TRUE;
}

// Class CBlockingSocket
IMPLEMENT_DYNAMIC(CBlockingSocket, CObject)

void CBlockingSocket::Cleanup()
{
 // doesn't throw an exception because it's called in a catch block
 if(m_hSocket == NULL) return;
 VERIFY(closesocket(m_hSocket) != SOCKET_ERROR);
 m_hSocket = NULL;
}

void CBlockingSocket::Create(int nType /* = SOCK_STREAM */)
{
 ASSERT(m_hSocket == NULL);
 if((m_hSocket = socket(AF_INET, nType, 0)) == INVALID_SOCKET)
 //指定了Inet協議,即TCP/IP協議,同時是利用面向連接的服務,
 //這樣以後的操作就是利用socket的標準函數進行的。
 //族爲 AF_INET, 類型爲已經設了默認SOCK_STREAM
 //由於該協議族中只有一個協議, 因此第三個參數爲 0
 {
  throw new CBlockingSocketException("Create");
 }
}

void CBlockingSocket::Bind(LPCSOCKADDR psa)
{
 ASSERT(m_hSocket != NULL);
 if(bind(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR)
 {
  throw new CBlockingSocketException("Bind");
 }
}

void CBlockingSocket::Listen()
{
 ASSERT(m_hSocket != NULL);
 if(listen(m_hSocket, 5) == SOCKET_ERROR) //指定了最大鏈接數爲5個
 {
  throw new CBlockingSocketException("Listen");
 }
}

BOOL CBlockingSocket::Accept(CBlockingSocket& sConnect, LPSOCKADDR psa)
{
 ASSERT(m_hSocket != NULL);
 ASSERT(sConnect.m_hSocket == NULL);
 int nLengthAddr = sizeof(SOCKADDR);
 sConnect.m_hSocket = accept(m_hSocket, psa, &nLengthAddr);
 if(sConnect == INVALID_SOCKET) {
  // no exception if the listen was canceled
  if(WSAGetLastError() != WSAEINTR) {
   throw new CBlockingSocketException("Accept");
  }
  return FALSE;
 }
 return TRUE;
}

void CBlockingSocket::Close()
{
 if (NULL == m_hSocket)
  return;

 if(closesocket(m_hSocket) == SOCKET_ERROR) {
  // should be OK to close if closed already
  throw new CBlockingSocketException("Close");
 }
 m_hSocket = NULL;
}

void CBlockingSocket::Connect(LPCSOCKADDR psa)
{
 ASSERT(m_hSocket != NULL);
 // should timeout by itself
 if(connect(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR) {
  throw new CBlockingSocketException("Connect");
 }
}

int CBlockingSocket::Write(const char* pch, const int nSize, const int nSecs)
{
 int nBytesSent = 0;
 int nBytesThisTime;
 const char* pch1 = pch;
 do {
  nBytesThisTime = Send(pch1, nSize - nBytesSent, nSecs);
  nBytesSent += nBytesThisTime;
  pch1 += nBytesThisTime;
 } while(nBytesSent < nSize);
 return nBytesSent;
}

int CBlockingSocket::Send(const char* pch, const int nSize, const int nSecs)
{
 ASSERT(m_hSocket != NULL);
 // returned value will be less than nSize if client cancels the reading
 FD_SET fd = {1, m_hSocket};
 TIMEVAL tv = {nSecs, 0};
 if(select(0, NULL, &fd, NULL, &tv) == 0) {
  throw new CBlockingSocketException("Send timeout");
 }
 int nBytesSent;
 if((nBytesSent = send(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR) {
  throw new CBlockingSocketException("Send");
 }
 return nBytesSent;
}

int CBlockingSocket::Receive(char* pch, const int nSize, const int nSecs)
{
 ASSERT(m_hSocket != NULL);
 FD_SET fd = {1, m_hSocket};
 TIMEVAL tv = {nSecs, 0};
 if(select(0, &fd, NULL, NULL, &tv) == 0) {
  throw new CBlockingSocketException("Receive timeout");
 }

 int nBytesReceived;
 if((nBytesReceived = recv(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR) {
  throw new CBlockingSocketException("Receive");
 }
 return nBytesReceived;
}

int CBlockingSocket::ReceiveDatagram(char* pch, const int nSize, LPSOCKADDR psa, const int nSecs)
{
 ASSERT(m_hSocket != NULL);
 FD_SET fd = {1, m_hSocket};
 TIMEVAL tv = {nSecs, 0};
 if(select(0, &fd, NULL, NULL, &tv) == 0) {
  throw new CBlockingSocketException("Receive timeout");
 }

 // input buffer should be big enough for the entire datagram
 int nFromSize = sizeof(SOCKADDR);
 int nBytesReceived = recvfrom(m_hSocket, pch, nSize, 0, psa, &nFromSize);
 if(nBytesReceived == SOCKET_ERROR) {
  throw new CBlockingSocketException("ReceiveDatagram");
 }
 return nBytesReceived;
}

int CBlockingSocket::SendDatagram(const char* pch, const int nSize, LPCSOCKADDR psa, const int nSecs)
{
 ASSERT(m_hSocket != NULL);
 FD_SET fd = {1, m_hSocket};
 TIMEVAL tv = {nSecs, 0};
 if(select(0, NULL, &fd, NULL, &tv) == 0) {
  throw new CBlockingSocketException("Send timeout");
 }

 int nBytesSent = sendto(m_hSocket, pch, nSize, 0, psa, sizeof(SOCKADDR));
 if(nBytesSent == SOCKET_ERROR) {
  throw new CBlockingSocketException("SendDatagram");
 }
 return nBytesSent;
}

void CBlockingSocket::GetPeerAddr(LPSOCKADDR psa)
{
 ASSERT(m_hSocket != NULL);
 // gets the address of the socket at the other end
 int nLengthAddr = sizeof(SOCKADDR);
 if(getpeername(m_hSocket, psa, &nLengthAddr) == SOCKET_ERROR) {
  throw new CBlockingSocketException("GetPeerName");
 }
}

void CBlockingSocket::GetSockAddr(LPSOCKADDR psa)
{
 ASSERT(m_hSocket != NULL);
 // gets the address of the socket at this end
 int nLengthAddr = sizeof(SOCKADDR);
 if(getsockname(m_hSocket, psa, &nLengthAddr) == SOCKET_ERROR) {
  throw new CBlockingSocketException("GetSockName");
 }
}

//static
CSockAddr CBlockingSocket::GetHostByName(const char* pchName, const USHORT ushPort /* = 0 */)
{
 hostent* pHostEnt = gethostbyname(pchName);
 if(pHostEnt == NULL) {
  throw new CBlockingSocketException("GetHostByName");
 }
 ULONG* pulAddr = (ULONG*) pHostEnt->h_addr_list[0];
 SOCKADDR_IN sockTemp;
 sockTemp.sin_family = AF_INET;
 sockTemp.sin_port = htons(ushPort);
 sockTemp.sin_addr.s_addr = *pulAddr; // address is already in network byte order
 return sockTemp;
}

//static
const char* CBlockingSocket::GetHostByAddr(LPCSOCKADDR psa)
{
 hostent* pHostEnt = gethostbyaddr((char*) &((LPSOCKADDR_IN) psa)
    ->sin_addr.s_addr, 4, PF_INET);
 if(pHostEnt == NULL) {
  throw new CBlockingSocketException("GetHostByAddr");
 }
 return pHostEnt->h_name; // caller shouldn't delete this memory
}

// Class CHttpBlockingSocket
IMPLEMENT_DYNAMIC(CHttpBlockingSocket, CBlockingSocket)

CHttpBlockingSocket::CHttpBlockingSocket()
{
 m_pReadBuf = new char[nSizeRecv];
 m_nReadBuf = 0;
}

CHttpBlockingSocket::~CHttpBlockingSocket()
{
 delete [] m_pReadBuf;
}

int CHttpBlockingSocket::ReadHttpHeaderLine(char* pch, const int nSize, const int nSecs)
// reads an entire header line through CRLF (or socket close)
// inserts zero string terminator, object maintains a buffer
{
 int nBytesThisTime = m_nReadBuf;
 int nLineLength = 0;
 char* pch1 = m_pReadBuf;
 char* pch2;
 do {
  // look for lf (assume preceded by cr)
  if((pch2 = (char*) memchr(pch1 , '/n', nBytesThisTime)) != NULL) {
   ASSERT((pch2) > m_pReadBuf);
   ASSERT(*(pch2 - 1) == '/r');
   nLineLength = (pch2 - m_pReadBuf) + 1;
   if(nLineLength >= nSize) nLineLength = nSize - 1;
   memcpy(pch, m_pReadBuf, nLineLength); // copy the line to caller
   m_nReadBuf -= nLineLength;
   memmove(m_pReadBuf, pch2 + 1, m_nReadBuf); // shift remaining characters left
   break;
  }
  pch1 += nBytesThisTime;
  nBytesThisTime = Receive(m_pReadBuf + m_nReadBuf, nSizeRecv - m_nReadBuf, nSecs);
  if(nBytesThisTime <= 0) { // sender closed socket or line longer than buffer
   throw new CBlockingSocketException("ReadHeaderLine");
  }
  m_nReadBuf += nBytesThisTime;
 }
 while(TRUE);
 *(pch + nLineLength) = '/0';
 return nLineLength;
}

int CHttpBlockingSocket::ReadHttpResponse(char* pch, const int nSize, const int nSecs)
// reads remainder of a transmission through buffer full or socket close
// (assume headers have been read already)
{
 int nBytesToRead, nBytesThisTime, nBytesRead = 0;
 if(m_nReadBuf > 0) { // copy anything already in the recv buffer
  memcpy(pch, m_pReadBuf, m_nReadBuf);
  pch += m_nReadBuf;
  nBytesRead = m_nReadBuf;
  m_nReadBuf = 0;
 }
 do { // now pass the rest of the data directly to the caller
  nBytesToRead = min(nSizeRecv, nSize - nBytesRead);
  nBytesThisTime = Receive(pch, nBytesToRead, nSecs);
  if(nBytesThisTime <= 0) break; // sender closed the socket
  pch += nBytesThisTime;
  nBytesRead += nBytesThisTime;
 }
 while(nBytesRead <= nSize);
 return nBytesRead;
}

void LogBlockingSocketException(LPVOID pParam, char* pch, CBlockingSocketException* pe)
{ // pParam holds the HWND for the destination window (in another thread)
 CString strGmt = CTime::GetCurrentTime().FormatGmt("%m/%d/%y %H:%M:%S GMT");
 char text1[200], text2[50];
 pe->GetErrorMessage(text2, 49);
 wsprintf(text1, "WINSOCK ERROR--%s %s -- %s/r/n", pch, text2, (const char*) strGmt);
 ::SendMessage((HWND) pParam, EM_SETSEL, (WPARAM) 65534, 65535);
 ::SendMessage((HWND) pParam, EM_REPLACESEL, (WPARAM) 0, (LPARAM) text1);
}

 

//+++++++++++++++++++++++++++++++

// clientinetthread.cpp (uses MFC Wininet calls)

#include <stdafx.h>
#include "utility.h"
#define MAXBUF 50000

HWND g_hMainWnd = 0;
char g_pchStatus[25] = "";
CCriticalSection g_csStatus;

UINT ClientWinInetThreadProc(LPVOID pParam)
{
 CCallbackInternetSession session;
 CHttpConnection* pConnection = NULL;
 CHttpFile* pFile1 = NULL;
 char* buffer = new char[MAXBUF];
 UINT nBytesRead = 0;
 DWORD dwStatus;
 try {
  // username/password doesn't work yet
  if(!g_strServerName.IsEmpty()) {
   pConnection = session.GetHttpConnection(g_strServerName,
     (INTERNET_PORT) g_nPort);
  }
  else {
   pConnection = session.GetHttpConnection(g_strServerIP,
     (INTERNET_PORT) g_nPort);
  }
  pFile1 = pConnection->OpenRequest(1, g_strFile, NULL, 1, NULL, NULL, // GET request
    INTERNET_FLAG_KEEP_CONNECTION); // needed for NT Challenge/Response authentication
    // INTERNET_FLAG_RELOAD forces reload from the server (bypasses client's cache)
  pFile1->SendRequest();
  pFile1->QueryInfoStatusCode(dwStatus);
  TRACE("QueryInfoStatusCode = %d/n", dwStatus);
  nBytesRead = pFile1->Read(buffer, MAXBUF - 1);
  buffer[nBytesRead] = '/0'; // necessary for message box
  char temp[100];
  if(pFile1->Read(temp, 100) != 0) { // makes caching work if read complete
   AfxMessageBox("File overran buffer -- not cached");
  }
  ::MessageBox(::GetTopWindow(::GetDesktopWindow()), buffer, "WININET CLIENT", MB_OK);
  // could use existing pFile1 to SendRequest again if we wanted to
 }
 catch(CInternetException* e) {
  LogInternetException(pParam, e);
  e->Delete();
 }
 // could call OpenRequest again on same connection if we wanted to
 if(pFile1) delete pFile1; // does the close -- prints a warning
 if(pConnection) delete pConnection; // why does it print a warning?
 delete [] buffer;
 g_csStatus.Lock();
   strcpy(g_pchStatus, ""); // problem with empty string. bug #9897
 g_csStatus.Unlock();
 return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章