// sockobj.h: interface for the csockobj class.////
#if! Defined (socketobj_h) #define socketobj_h
#if _MSC_VER> 1000 # prgma overce # endif //_MSC_VER> 1000
#include "../std.h"
const int SOCKET_SUCCESS = 0; // success flag corresponding to the SOCKET_ERROR const int _SOCKET_MAJOR_VERSION = 2; const int _SOCKET_MINOR_VERSION = 2; const int _LISTEN_COUNT = 200; const DWORD _SHUTDOWN_RECV_TIMEOUT = 4 * 1000; 4 seconds delay // const DWORD perfectly closed when _RECV_TIMEOUT = 120; // 120 seconds to receive timeout const dword _send_timeout = 120; // 120 seconds Send timeout const dword _Accept_timeout = 12; // 120 seconds to accept timeout const dword _blocked_sndrcv_sleep = 100; // 100 milliseconds (waiting when blocking occurs Sleep] Time) Const DWORD _RECV_BUFF_LEN = 8192;
Bool GetipBysock (socket Sock, Char * IP);
Class csockobj {public: csockobj (); virtual ~ csockobj ();
PUBLIC: Static Void Cleanuplibrary (Void); Static Int Initlibrary (VOID);
Protected: int m_nerrorno;
PUBLIC: // Create a socket createsocket with overlapping IO capabilities (int NADDRESSFAMILY = AF_INET, INT NPROTOCOL = 0); // Sets the socket property int setsocketoption (Socket HSocket);
// Set whether the socket is blocking int blocksocket (socket hsocket, bool bblock);
// Binding socket INT Bindsocketex (socket hsocket, int nport); // Basic parameter Binding Socket INT Bindsocket (Socket HSocket, Struct SockAddr * PsocketAddress, INT NADDRLEN); / / Connection Skin Int Connect sOCKET hSocket, const char * pIP, int nPort); // listening socket int ListenSocket (sOCKET hSocket, int nConnections = _LISTEN_COUNT); // blocked ACCEPT, no response is not returned sOCKET Accept_Block (sOCKET hSocket, struct sockaddr * pSocketAddress = NULL, INT * NADDRLEN = NULL);
// Asynchronous Accept, timeout Return to Socket Accept (Socket HSocket, Struct SockAddr * psocketaddress = null, int * Naddrlen = NULL, DWORD DWTIMEOUT = _ACCEPT_TIMEOUT);
// int RecvDataFrom_Block (SOCKET hSocket, struct sockaddr * pFrom, int nAddrlen, // char * pszBuffer, int nBufferSize, DWORD dwTimeout = _RECV_TIMEOUT); // blocking receive data, the function is turned off to stop the port (received length 0), or when an error int RecvData_Block (SOCKET hSocket, char * pszBuffer, int nBufferSize, DWORD dwTimeout = _RECV_TIMEOUT); int RecvData_Event (SOCKET hSocket, char * pszBuffer, int nBufferSize, DWORD dwTimeout = _RECV_TIMEOUT); // Receive all Data, Note Before this function call must be confirmed whether there is reception message to Int Recvdata (socket hsocket, char * pszbuffer, int nbuffersize);
// transmit all data in the buffer, the blocking int SendData_Block (SOCKET hSocket, char const * pszBuffer, int nBufferSize, DWORD dwTimeout = _SEND_TIMEOUT); // send data, blocking int Send_Block (SOCKET hSocket, char const * pszBuffer, int nBufferSize, DWORD DWTIMEOUT = _SEND_TIMEOUT;
// Send a buffer data, but there may be not all sent // int send_event (socket hsocket, char const * pszbuffer, int nbuffearsize, // dword dwtimeout = _send_timeout); // Close the socket Void CloseSocket (Socket HSocket, Bool bhardClose = false;
Inline Void SetLastError (INT IerrorCode) // Setup Error Code {InterlockedExchange ((LPLONG) & M_NerrorNo, IrrorCode);
Inline int getLastError () // Gets the most recent error code {INT IERRORNO; InterlocKedexchange ((LPLONG) & IrrorNo, M_NerrorNo;};}; # include "sockobj.h"
Bool GetipBysock (Socket Sock, Char * IP) {struct sockaddr sa; int len = sizeof (sa);
IF (0! = getPeername (Sock, & Sa, & Len) Return False;
For (size_t i = 0; i <6; i) {ip [i] = sa.sa_data [i 2];
Return True;}
CSOCKOBJ :: CSOCKOBJ () {}
CsockObj :: ~ csockobj () {// cleanuplibrary ();
Void CsockObj :: Cleanuplibrary (void) {wsacleanup ();}
int CSockObj :: InitLibrary (void) {WSADATA WSD; WORD wVersionRequired = MAKEWORD (_SOCKET_MAJOR_VERSION, _SOCKET_MINOR_VERSION); ZeroMemory (& WSD, sizeof (WSADATA)); int nErrorNo = WSAStartup (wVersionRequired, & WSD); if (! SOCKET_SUCCESS = nErrorNo) { // SetLastError (nErrorNo); return (SOCKET_ERROR); (!! LOBYTE (WSD.wVersion) = _SOCKET_MINOR_VERSION || hIBYTE (WSD.wVersion) = _SOCKET_MAJOR_VERSION)} if {WSACleanup (); // SetLastError (WSAVERNOTSUPPORTED); return ( Socket_ERROR);} // Successfully initialization return (socket_success);} // Settings Socket Properties // Entrance: Socket // Exit: Return 0, Error Return -1Int Csockobj :: SetSocketoption (Socket Hsocket) {int nActivate = 1; // allow address reuse if (setsockopt (hSocket, SOL_SOCKET, SO_REUSEADDR, (const char *) & nActivate, sizeof (nActivate)) == SOCKET_ERROR) {SetLastError (WSAGetLastError ()); return (SOCKET_ERROR); // Return (-1)} / * bool bdontlinger = true; if (setsockopt (hsockopt (hsocket, sol_socket, so_dontlinger, (const char *) & bdontlinger, sizeof (bdontlinger) == Socke T_ERROR) {setLastError (wsagetlasterror ()); return (socket_error); // Return (-1)} linger linger = {0,0}; if (setsockopt (hsockopt (hsocket, sol_socket, so_linger, (const char *) & linger, sizeof (Linger) == SOCKET_ERROR) {setLastError ()); return (socket_error); // Return (-1)} * / return (socket_success);}
/ / Set whether the socket is blocking // entry: Socket /) {u_long IoctlLong = (bBlock) 0:? 1; if (ioctlsocket (hSocket, FIONBIO, & IoctlLong) == SOCKET_ERROR) {SetLastError (WSAGetLastError ()); return (SOCKET_ERROR);} return (SOCKET_SUCCESS);} int CSockObj :: Connect (SOCKET hSocket, const char * pIP, int nPort) {SOCKADDR_IN sockAddr; ZeroMemory (& sockAddr, sizeof (sockAddr)); sockAddr.sin_family = AF_INET; sockAddr.sin_addr.s_addr = inet_addr (pIP); sockAddr.sin_port = Htons ((u_short) nPort;
Return Connect (HSocket, Struct SockAddr *) & SockAddr, Sizeof (SockAddr_IN));
// Close the socket // Entrance: Socket Capture error if (! BhardClose) // Elegant closing graceful close {// no longer sends data, for TCP socket, after all data is sent, // will send a FIN, notify the recipient all data has been sent complete. Shutdown (hsocket, sd_send);
/ / The receiving buffer may have unrepaired data, and should read the residual data before turning off the socket. INT NRECVRESULT; Handle HSocketevent = CreateEvent (NULL, FALSE, FALSE, NULL); / / Subbeller CHAR SZBuffer [256] provided for residual data; do {if (hsocketevent! = null) {// Register Network Event WSAEventSelect (HSocket) , (WSAEVENT) hSocketEvent, FD_READ | FD_CLOSE); WSAWaitForMultipleEvents (1, & hSocketEvent, TRUE, _SHUTDOWN_RECV_TIMEOUT, TRUE); // Clear network events WSAEventSelect (hSocket, (WSAEVENT) hSocketEvent, 0);} ZeroMemory (szBuffer, 256); / / Receive Residual Data NRECVRESULT = Recvdata (HSocket, Szbuffer, Sizeof (Szbuffer);} While (NRECVRESULT> 0);
IF (hsocketevent! = null) CloseHandle (HSocketevent); // no longer allows reception and sending shutdown (hsocket, sd_both);} // Close the socket IF (0! = hsocket) CloseSocket (HSocket);
// Binding socket // Entrance: Socket (Bind (HSOCKET, PSOCKETDRESS, NADDRLEN) == Socket_ERROR) {setLastError ()); return (socket_error);} return (socket_success);} // Binding socket // Entrance: socket, port number // Exit: Correct 0, error - 1int CsockObj :: Bindsocketex (socket hsocket, int nport) {sockaddr_in sockaddr; zeromeMory (& SockAddr, sizeof (socketdr));
Sockaddr.sin_Family = AF_INET; SOCKADDR.SIN_ADDR.S_ADDR = HTONL (INADDR_Addr_Anddr_Anddr_Port = HTONS ((u_short) Nport;
Return Bindsocket (HSocket, (SockAddr *) & SockAddr, Sizeof (SockAddr);
// Create a socket // entry with overlapping IO capabilities: protocol, protocol type (TCP / U), protocol // Exit: Return to created overlapping IO Socket // Caution: Use socket () functions created Sockets the ability to have overlapping default IO SOCKET CSockObj :: createSocket (int nAddressFamily / * = AF_INET * /, int nType / * = SOCK_STREAM * /, int nProtocol / * = 0 * /) {SOCKET hSocket = WSASocket (nAddressFamily, nType, nProtocol, NULL, 0, WSA_FLAG_OVERLERLAPPED; if (hsocket == invalid_socket) {setLastError (WsagetLastError ()); return (invalid_socket);}
// Setting the socket option if (socket_error == setsocketoption (hsocket)) // Setting the properties failed {CloseSocket (hsocket, true); return (invalid_socket);} return (hsocket);
// Block Accept, no response does not return // Entrance: socket, host address, length // Exit: Return to the port number correctly, otherwise return to invalid_socketsocket csockobj :: Accept_block (Socket HSocket, Struct SockAddr * PsocketAddress, int * Naddrlen) {If (invalid_socket == hsocket) return (invalid_socket); socket Haccept = Accept (HSocket, PsocketAddress, Naddrlen);
// If the port error If (invalid_socket == HACCEPT) setLastError ()); return hacerpt;}
SOCKET CSockObj :: Accept (SOCKET hSocket, struct sockaddr * pSocketAddress, int * nAddrLen, DWORD dwTimeout) {if (INVALID_SOCKET == hSocket) return (SOCKET_ERROR); // dwTimeout = 1000 * 1000; SOCKET hAccept; bool bNodelay; FD_SET fd = {1, hsocket}; timeval TV = {dwtimeout, 0}; unsigned long flag = 1; int nbytessent = 0; // printf ("Enter SELECT% D TIME =% D / R / N", HSocket, DWTIMEOUT) INT Ierror = SELECT (0, & FD, NULL, NULL, & TV); if (ierror == 0) {// printf ("Leave SELECT / R / N"); goto clear; // Select Send Time: Else IF (Socket_error == Irror) {// printf ("select error / r / n");} else {harcept = accept (hsocket, psocketaddress, naddrlen); // If the port error If (invalid_socket == HACCEPT) setLastError WSAGetLastError ()); else {setsockopt (hAccept, IPPROTO_TCP, TCP_NODELAY, (char *) & bNodelay, sizeof (bNodelay)); // ioctlsocket (hAccept, FIONBIO, & flag);} return hAccept;} CLEAR: SetLastError (WSAGetLastError () ); // Timeout Return (Invalid_Socket);
// Listening Socket // Entrance: Socket ) {SetLastError ()); return (socket_error);} return (socket_success);}
// block the received data, the function stops when the port is turned off (receiving length 0), or an incorrect // entry: socket, receive buffers, and length, timeout // Exit: Return to receive correctly length, otherwise SOCKET_ERRORint CSockObj :: RecvData_Block (SOCKET hSocket, char * pszBuffer, int nBufferSize, DWORD dwTimeout) {if (hSocket == INVALID_SOCKET || pszBuffer == NULL) return (SOCKET_ERROR);
// dwtimeout = 1000 * 1000; fd_set fd = {1, hsocket}; timeval TV = {dwtimeout, 0}; int nbytesReceived = 0; int nselectret = SELECT (0, & fd, null, null, & TV); // Return When the value of greater than 0, it indicates that the Socket number // returns 0 indicates that time // returns SOCKET_ERROR IF (0 == NSELECTRET || // Timeout socket_error == nselectret) // Socket Error Goto Clear; IF ((NBYTESRECEIVED = Recv (HSocket, Pszbuffer, NBuffersize, 0)) == Socket_ERROR) Goto clear; // Return to received bytes when successfully. // Return to SOCKET_ERROR when the connection is interrupted Return nbytesReceive;
CLEAR: SetLastError (Wsagetlasterror ()); // Timeout Return (Socket_ERROR);
/ / Receive all data, pay attention to whether you must confirm if there is a received message arrival // Entrance: socket, data buffer, buffer size // Exit: Returns the number of bytes received correctly, error returns Error Code Int Csockobj :: Recvdata (Socket HSocket, CHAR * PSZBuffer, INT NBUFFERSIZE) {if (hsocket == invalid_socket || pszbuffer == NULL) Return (socket_error);
DWORD DWRTXBYTES = 0, DWRTXFLAGS = 0; WSABUF WSABUFF;
/ / Clear buffer ZeromeMory (& WSABUFF, SIZEOF (WSABUF));
Wsabuff.len = nbuffersize; wsabuff.buf = pszbuffer; // Returns the number of bytes of this reception if it is correct, if the error returns the error number (negative number) Return ((Wsarecv (HSArCV (HSATXBYTES, & DWRTXFLAGS, NULL, NULL) == SOCKET_SUCCESS? (Int) dwrtxbytes: -wsagetlasterror ());}
/ / Receive data (blocked until the data is received) // Entrance: socket, data buffer, buffer size, timeout // Exit: If the received byte is correct, the error returns an error code INT CSOCKOBJ :: Recvdata_Event (socket hszbuffet, int nbuffersize, dword dwtimeout) {if (hsocket == invalid_socket || pszbuffer == null) Return (socket_error);
Handle HreadEvent = CreateEvent (NULL, FALSE, FALSE, NULL); if (hreadevent == null) {setLastError ((int) getLastError ()); return (socket_error);}
INT NRECVBYTES = 0; DWORD DWWAITRESUT; for (;;) {// Register FD_READ | FD_CLOSE Event // (Because the other party closes the socket, you have to pay attention to fd_closelect "if (WSAEventSelect (hsAeventselect (hsocket) WSAEVENT) hReadEvent, FD_READ | FD_CLOSE) == SOCKET_ERROR) {CloseHandle (hReadEvent); SetLastError (WSAGetLastError ()); return (SOCKET_ERROR);} // etc. FD_READ | event occurs dwWaitResult FD_CLOSE = WSAWaitForMultipleEvents (1, & hReadEvent, TRUE DWTIMEOUT, TRUE;
if (! dwWaitResult = WSA_WAIT_EVENT_0) {// Clear the event WSAEventSelect (hSocket, (WSAEVENT) hReadEvent, 0); CloseHandle (hReadEvent); SetLastError (WSAGetLastError ()); return (SOCKET_ERROR);} // /// Note: Even dwWaitResult == WSA_WAIT_EVENT0, should also check whether the network is further /// /// WSANETWORKEVENTS NetEvent error occurs; if (hReadEvent WSAEnumNetworkEvents (hSocket, (WSAEVENT), & NetEvent) == SOCKET_ERROR) {// Clear the event WSAEventSelect (hSocket, (WSAEVENT ) hReadEvent, 0); CloseHandle (hReadEvent); SetLastError (WSAGetLastError ()); return (SOCKET_ERROR);} // determines what event occurred or FD_READ FD_CLOSE if ((NetEvent.lNetworkEvents == FD_CLOSE) || (NetEvent.lNetworkEvents ! == FD_READ && NetEvent.iErrorCode [FD_READ_BIT] = 0)) // error {// clear the event WSAEventSelect (hSocket, (WSAEVENT) hReadEvent, 0); CloseHandle (hReadEvent); SetLastError (WSAGetLastError ()); return ( Socket_ERROR);} // Clear event WSAEventSelect (HSocket, (wsaevent) HREADEVENT, 0); // Receive Data Printf ("Socket [% D] INTO Recvdata / R / N", HS Ocket); if (NRECvBytes = Recvdata (hsocket, pszbuffer, nbuffers)> = 0) BREAK; // Take a loop printf ("Socket [% D] Into Recvdata, NRECVBYTES =% D / R / N", HSocket, NRECVBYTES; // RECV returns the negative number of error code, so it needs to be transferred to int NERRORCODE = -nrecvbytes; if (NerrorCode! = wsaewouldblock) // Too much unfinished overlapping operation {CloseHandle (HREADEVENT); setLastEvent; setLastEvent (NERRRCODE) Return (Socket_ERROR);} // Blocking Sleep (_Blocked_SNDRCV_SLEP);} CloseHandle (HREADEVENT); Printf ("Socket [% D] Out Recvdata / R / N", hsocket); return (nRvbytes);}
// Send data, block // Entrance: Socket = INVALID_SOCKET || = INVALN (SOCKET_ERROR); fd_set fd = {1, hsocket}; timevalval TV = {dwtimeout, 0}; int nbytessent = 0; if (SELECT (0, Null, & fd, Null, & TV) ) == 0) goto clear; // Select Send Timeout IF ((Nbytessent = Send (HSocket, Pszbuffer, NBuffersize, 0)) == Socket_ERROR) Goto clear; // Send Error Return nbytessent;
CLEAR: SetLastError (Wsagetlasterror ()); // Timeout Return (Socket_ERROR);
// Send all buffer data, block // entrance: socket, send strings, strings length, timeout value // exit: Return the number of bytes sent by send, Error Return Socket_ERRORINT CSOCKOBJ :: Senddata_block (Socket HSocket, Char const * pszbuffer, int NBuffersize, DWORD DWTIMEOUT
{IF (hsocket == invalid_socket || pszbuffer == null) Return (socket_error);
int nBytesSent = 0; int nBytesThisTime; const char * pszTemp = pszBuffer; do {nBytesThisTime = Send_Block (hSocket, pszTemp, nBufferSize-nBytesSent, dwTimeout); if (nBytesThisTime <0) return (SOCKET_ERROR); // If a transmission is not successful NBYTESSENT = nbytesthistime; // Change the current character pointer psztemp = nbytesthistime;} while (nbytessent