Blocksock.cpp
上传用户:swkcbjrc
上传日期:2016-04-02
资源大小:45277k
文件大小:9k
源码类别:

游戏

开发平台:

Visual C++

  1. // blocksock.cpp (CBlockingSocketException, CBlockingSocket, CHttpBlockingSocket)
  2. #include <stdafx.h>
  3. #include "blocksock.h"
  4. // Class CBlockingSocketException
  5. IMPLEMENT_DYNAMIC(CBlockingSocketException, CException)
  6. CBlockingSocketException::CBlockingSocketException(char* pchMessage)
  7. {
  8. m_strMessage = pchMessage;
  9. m_nError = WSAGetLastError();
  10. }
  11. BOOL CBlockingSocketException::GetErrorMessage(LPTSTR lpstrError, UINT nMaxError,
  12. PUINT pnHelpContext /*= NULL*/)
  13. {
  14. char text[200];
  15. if(m_nError == 0) {
  16. wsprintf(text, "%s error", (const char*) m_strMessage);
  17. }
  18. else {
  19. wsprintf(text, "%s error #%d", (const char*) m_strMessage, m_nError);
  20. }
  21. strncpy(lpstrError, text, nMaxError - 1);
  22. return TRUE;
  23. }
  24. // Class CBlockingSocket
  25. IMPLEMENT_DYNAMIC(CBlockingSocket, CObject)
  26. void CBlockingSocket::Cleanup()
  27. {
  28. // doesn't throw an exception because it's called in a catch block
  29. if(m_hSocket == NULL) return;
  30. VERIFY(closesocket(m_hSocket) != SOCKET_ERROR);
  31. m_hSocket = NULL;
  32. }
  33. void CBlockingSocket::Create(int nType /* = SOCK_STREAM */)
  34. {
  35. ASSERT(m_hSocket == NULL);
  36. if((m_hSocket = socket(AF_INET, nType, 0)) == INVALID_SOCKET) {
  37. throw new CBlockingSocketException("Create");
  38. }
  39. }
  40. void CBlockingSocket::Bind(LPCSOCKADDR psa)
  41. {
  42. ASSERT(m_hSocket != NULL);
  43. if(bind(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR) {
  44. throw new CBlockingSocketException("Bind");
  45. }
  46. }
  47. void CBlockingSocket::Listen()
  48. {
  49. ASSERT(m_hSocket != NULL);
  50. if(listen(m_hSocket, 5) == SOCKET_ERROR) {
  51. throw new CBlockingSocketException("Listen");
  52. }
  53. }
  54. BOOL CBlockingSocket::Accept(CBlockingSocket& sConnect, LPSOCKADDR psa)
  55. {
  56. ASSERT(m_hSocket != NULL);
  57. ASSERT(sConnect.m_hSocket == NULL);
  58. int nLengthAddr = sizeof(SOCKADDR);
  59. sConnect.m_hSocket = accept(m_hSocket, psa, &nLengthAddr);
  60. if(sConnect == INVALID_SOCKET) {
  61. // no exception if the listen was canceled
  62. if(WSAGetLastError() != WSAEINTR) {
  63. throw new CBlockingSocketException("Accept");
  64. }
  65. return FALSE;
  66. }
  67. return TRUE;
  68. }
  69. void CBlockingSocket::Close()
  70. {
  71. ASSERT(m_hSocket != NULL);
  72. if(closesocket(m_hSocket) == SOCKET_ERROR) {
  73. // should be OK to close if closed already
  74. throw new CBlockingSocketException("Close");
  75. }
  76. m_hSocket = NULL;
  77. }
  78. void CBlockingSocket::Connect(LPCSOCKADDR psa)
  79. {
  80. ASSERT(m_hSocket != NULL);
  81. // should timeout by itself
  82. if(connect(m_hSocket, psa, sizeof(SOCKADDR)) == SOCKET_ERROR) {
  83. throw new CBlockingSocketException("Connect");
  84. }
  85. }
  86. int CBlockingSocket::Write(const char* pch, const int nSize, const int nSecs)
  87. {
  88. int nBytesSent = 0;
  89. int nBytesThisTime;
  90. const char* pch1 = pch;
  91. do {
  92. nBytesThisTime = Send(pch1, nSize - nBytesSent, nSecs);
  93. nBytesSent += nBytesThisTime;
  94. pch1 += nBytesThisTime;
  95. } while(nBytesSent < nSize);
  96. return nBytesSent;
  97. }
  98. int CBlockingSocket::Send(const char* pch, const int nSize, const int nSecs)
  99. {
  100. ASSERT(m_hSocket != NULL);
  101. // returned value will be less than nSize if client cancels the reading
  102. FD_SET fd = {1, m_hSocket};
  103. TIMEVAL tv = {nSecs, 0};
  104. if(select(0, NULL, &fd, NULL, &tv) == 0) {
  105. throw new CBlockingSocketException("Send timeout");
  106. }
  107. int nBytesSent;
  108. if((nBytesSent = send(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR) {
  109. throw new CBlockingSocketException("Send");
  110. }
  111. return nBytesSent;
  112. }
  113. int CBlockingSocket::Receive(char* pch, const int nSize, const int nSecs)
  114. {
  115. ASSERT(m_hSocket != NULL);
  116. FD_SET fd = {1, m_hSocket};
  117. TIMEVAL tv = {nSecs, 0};
  118. if(select(0, &fd, NULL, NULL, &tv) == 0) {
  119. throw new CBlockingSocketException("Receive timeout");
  120. }
  121. int nBytesReceived;
  122. if((nBytesReceived = recv(m_hSocket, pch, nSize, 0)) == SOCKET_ERROR) {
  123. throw new CBlockingSocketException("Receive");
  124. }
  125. return nBytesReceived;
  126. }
  127. int CBlockingSocket::ReceiveDatagram(char* pch, const int nSize, LPSOCKADDR psa, const int nSecs)
  128. {
  129. ASSERT(m_hSocket != NULL);
  130. FD_SET fd = {1, m_hSocket};
  131. TIMEVAL tv = {nSecs, 0};
  132. if(select(0, &fd, NULL, NULL, &tv) == 0) {
  133. throw new CBlockingSocketException("Receive timeout");
  134. }
  135. // input buffer should be big enough for the entire datagram
  136. int nFromSize = sizeof(SOCKADDR);
  137. int nBytesReceived = recvfrom(m_hSocket, pch, nSize, 0, psa, &nFromSize);
  138. if(nBytesReceived == SOCKET_ERROR) {
  139. throw new CBlockingSocketException("ReceiveDatagram");
  140. }
  141. return nBytesReceived;
  142. }
  143. int CBlockingSocket::SendDatagram(const char* pch, const int nSize, LPCSOCKADDR psa, const int nSecs)
  144. {
  145. ASSERT(m_hSocket != NULL);
  146. FD_SET fd = {1, m_hSocket};
  147. TIMEVAL tv = {nSecs, 0};
  148. if(select(0, NULL, &fd, NULL, &tv) == 0) {
  149. throw new CBlockingSocketException("Send timeout");
  150. }
  151. int nBytesSent = sendto(m_hSocket, pch, nSize, 0, psa, sizeof(SOCKADDR));
  152. if(nBytesSent == SOCKET_ERROR) {
  153. throw new CBlockingSocketException("SendDatagram");
  154. }
  155. return nBytesSent;
  156. }
  157. void CBlockingSocket::GetPeerAddr(LPSOCKADDR psa)
  158. {
  159. ASSERT(m_hSocket != NULL);
  160. // gets the address of the socket at the other end
  161. int nLengthAddr = sizeof(SOCKADDR);
  162. if(getpeername(m_hSocket, psa, &nLengthAddr) == SOCKET_ERROR) {
  163. throw new CBlockingSocketException("GetPeerName");
  164. }
  165. }
  166. void CBlockingSocket::GetSockAddr(LPSOCKADDR psa)
  167. {
  168. ASSERT(m_hSocket != NULL);
  169. // gets the address of the socket at this end
  170. int nLengthAddr = sizeof(SOCKADDR);
  171. if(getsockname(m_hSocket, psa, &nLengthAddr) == SOCKET_ERROR) {
  172. throw new CBlockingSocketException("GetSockName");
  173. }
  174. }
  175. //static
  176. CSockAddr CBlockingSocket::GetHostByName(const char* pchName, const USHORT ushPort /* = 0 */)
  177. {
  178. hostent* pHostEnt = gethostbyname(pchName);
  179. if(pHostEnt == NULL) {
  180. throw new CBlockingSocketException("GetHostByName");
  181. }
  182. ULONG* pulAddr = (ULONG*) pHostEnt->h_addr_list[0];
  183. SOCKADDR_IN sockTemp;
  184. sockTemp.sin_family = AF_INET;
  185. sockTemp.sin_port = htons(ushPort);
  186. sockTemp.sin_addr.s_addr = *pulAddr; // address is already in network byte order
  187. return sockTemp;
  188. }
  189. //static
  190. const char* CBlockingSocket::GetHostByAddr(LPCSOCKADDR psa)
  191. {
  192. hostent* pHostEnt = gethostbyaddr((char*) &((LPSOCKADDR_IN) psa)
  193. ->sin_addr.s_addr, 4, PF_INET);
  194. if(pHostEnt == NULL) {
  195. throw new CBlockingSocketException("GetHostByAddr");
  196. }
  197. return pHostEnt->h_name; // caller shouldn't delete this memory
  198. }
  199. // Class CHttpBlockingSocket
  200. IMPLEMENT_DYNAMIC(CHttpBlockingSocket, CBlockingSocket)
  201. CHttpBlockingSocket::CHttpBlockingSocket()
  202. {
  203. m_pReadBuf = new char[nSizeRecv];
  204. m_nReadBuf = 0;
  205. }
  206. CHttpBlockingSocket::~CHttpBlockingSocket()
  207. {
  208. delete [] m_pReadBuf;
  209. }
  210. int CHttpBlockingSocket::ReadHttpHeaderLine(char* pch, const int nSize, const int nSecs)
  211. // reads an entire header line through CRLF (or socket close)
  212. // inserts zero string terminator, object maintains a buffer
  213. {
  214. int nBytesThisTime = m_nReadBuf;
  215. int nLineLength = 0;
  216. char* pch1 = m_pReadBuf;
  217. char* pch2;
  218. do {
  219. // look for lf (assume preceded by cr)
  220. if((pch2 = (char*) memchr(pch1 , 'n', nBytesThisTime)) != NULL) {
  221. ASSERT((pch2) > m_pReadBuf);
  222. ASSERT(*(pch2 - 1) == 'r');
  223. nLineLength = (pch2 - m_pReadBuf) + 1;
  224. if(nLineLength >= nSize) nLineLength = nSize - 1;
  225. memcpy(pch, m_pReadBuf, nLineLength); // copy the line to caller
  226. m_nReadBuf -= nLineLength;
  227. memmove(m_pReadBuf, pch2 + 1, m_nReadBuf); // shift remaining characters left
  228. break;
  229. }
  230. pch1 += nBytesThisTime;
  231. nBytesThisTime = Receive(m_pReadBuf + m_nReadBuf, nSizeRecv - m_nReadBuf, nSecs);
  232. if(nBytesThisTime <= 0) { // sender closed socket or line longer than buffer
  233. throw new CBlockingSocketException("ReadHeaderLine");
  234. }
  235. m_nReadBuf += nBytesThisTime;
  236. }
  237. while(TRUE);
  238. *(pch + nLineLength) = '';
  239. return nLineLength;
  240. }
  241. int CHttpBlockingSocket::ReadHttpResponse(char* pch, const int nSize, const int nSecs)
  242. // reads remainder of a transmission through buffer full or socket close
  243. // (assume headers have been read already)
  244. {
  245. int nBytesToRead, nBytesThisTime, nBytesRead = 0;
  246. if(m_nReadBuf > 0) { // copy anything already in the recv buffer
  247. memcpy(pch, m_pReadBuf, m_nReadBuf);
  248. pch += m_nReadBuf;
  249. nBytesRead = m_nReadBuf;
  250. m_nReadBuf = 0;
  251. }
  252. do { // now pass the rest of the data directly to the caller
  253. nBytesToRead = min(nSizeRecv, nSize - nBytesRead);
  254. nBytesThisTime = Receive(pch, nBytesToRead, nSecs);
  255. if(nBytesThisTime <= 0) break; // sender closed the socket
  256. pch += nBytesThisTime;
  257. nBytesRead += nBytesThisTime;
  258. }
  259. while(nBytesRead <= nSize);
  260. return nBytesRead;
  261. }
  262. void LogBlockingSocketException(LPVOID pParam, char* pch, CBlockingSocketException* pe)
  263. { // pParam holds the HWND for the destination window (in another thread)
  264. /* CString strGmt = CTime::GetCurrentTime().FormatGmt("%m/%d/%y %H:%M:%S GMT");
  265. char text1[200], text2[50];
  266. pe->GetErrorMessage(text2, 49);
  267. wsprintf(text1, "WINSOCK ERROR--%s %s -- %srn", pch, text2, (const char*) strGmt);
  268. ::SendMessage((HWND) pParam, EM_SETSEL, (WPARAM) 65534, 65535);
  269. ::SendMessage((HWND) pParam, EM_REPLACESEL, (WPARAM) 0, (LPARAM) text1);
  270. */
  271. }