#ifdef _WIN32 // #include //#include #include typedef int socklen_t; #else //!WIN32 #include #include #include #include #include #endif #include #include #include "typedef.h" #include "debug.h" #include "Socket.h" ////////////////////////////////////////////////////////////////////////// // CSocket // CSocket::CSocket() { m_bOpen = false; m_skt = 0; } CSocket::~CSocket() { int ret = 0; if( IsOpen() ){ ret = Close(); } if( m_skt>0 && ret==0 ){ closesocket (m_skt); m_skt = 0; } else{ int err = GetLastError(); DebugPrint( "Close error code=%d.\n", err ); } } int CSocket::Close() { if( m_bOpen && m_skt>0 ){ m_bOpen = false; return shutdown( m_skt, 0x02 ); } return -1; } bool CSocket::GetLocalAddr(char *sAddr) { if (!sAddr) return false; SOCKADDR_IN addr; #ifdef __MACOSX__ UINT nSize = sizeof(addr); #else int nSize = sizeof(addr); #endif if (::getsockname(m_skt,(struct sockaddr*)&addr,(socklen_t*)&nSize)==SOCKET_ERROR) return false; char *pb=(char *)&(addr.sin_addr); unsigned b1=(unsigned char)(*pb); unsigned b2=(unsigned char)(*(pb+1)); unsigned b3=(unsigned char)(*(pb+2)); unsigned b4=(unsigned char)(*(pb+3)); sprintf(sAddr,"%d.%d.%d.%d",b1,b2,b3,b4); return true; } bool CSocket::SetOption(int option,const void * valuePtr,unsigned int valueSize) { return (::setsockopt(m_skt,IPPROTO_IP,option,(char *)valuePtr,valueSize)==0); } int CSocket::SetNonblock( bool bNonblock ) { int ret = 0; DWORD fionbio = bNonblock; if( ioctlsocket(m_skt, FIONBIO, &fionbio)==SOCKET_ERROR ){ ret = GetLastError(); DebugPrint("ioctlsocket Error = %d\n", ret ); } return ret; } int CSocket::WaitForReading(int nSeconds ) { // SetNonblock( true ); // DebugPrint( "socket wait for reading.\n" ); fd_set rfd; FD_ZERO(&rfd); FD_SET(m_skt,&rfd); timeval tv; tv.tv_sec = nSeconds;//等待时间 tv.tv_usec = 0; int ret; // while( true ){ ret = select(m_skt+1, &rfd, NULL, NULL, &tv); // if( ret==0 || ret==SOCKET_ERROR || FD_ISSET(m_skt, &rfd)){ // break; // } // } // DebugPrint( "socket wait for reading return %d\n", ret ); if( ret==1 ){ if( !FD_ISSET(m_skt, &rfd) ){ // DebugPrint( "SetNonblock\n" ); // SetNonblock( false ); ret = SOCKET_ERROR; } } return ret; } // ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// // CUDPSocket // CUDPSocket::CUDPSocket() { m_skt = socket (AF_INET, SOCK_DGRAM, 0); if (m_skt == INVALID_SOCKET){ DebugPrint("Can't open UDP socket\n"); m_bOpen = false; int nErrorCode = GetLastError(); return; } m_bOpen = true; m_nPacketLen = 0; m_nCur = 0; } CUDPSocket::CUDPSocket(unsigned short nPort,bool bRaw) { if( bRaw ){ m_skt = socket (AF_INET,SOCK_RAW,108); } else{ m_skt = socket (AF_INET,SOCK_DGRAM,0); } if (m_skt == INVALID_SOCKET){ DebugPrint("Can't open UDP socket\n"); m_bOpen = false; int nErrorCode = GetLastError(); return; } SOCKADDR_IN local_sin; memset(&local_sin, 0, sizeof(local_sin) ); local_sin.sin_family = AF_INET; local_sin.sin_port = htons (nPort); local_sin.sin_addr.s_addr = htonl(INADDR_ANY); if (bind (m_skt,(struct sockaddr *) &local_sin,sizeof (sockaddr)) == SOCKET_ERROR){ DebugPrint("Binding Error\n"); // Close(); return; } m_bOpen = true; m_nPacketLen = 0; m_nCur = 0; } CUDPSocket::CUDPSocket(unsigned int ipAddr,unsigned short nPort,bool bRaw) { if( bRaw ){ m_skt = socket (AF_INET,SOCK_RAW,108); } else{ m_skt = socket (AF_INET,SOCK_DGRAM,0); } if (m_skt == INVALID_SOCKET){ DebugPrint("Can't open UDP socket\n"); int nError=GetLastError(); DebugPrint("CUDPSocket::CUDPSocket Socket Error = %d\n",nError); m_bOpen = false; return; } /* if( SetNonblock( true )!=0 ){ return; } */ memset(&ptop, 0, sizeof(ptop) ); ptop.sin_family=AF_INET; ptop.sin_addr.s_addr=ipAddr; ptop.sin_port=htons(nPort); /* for(int bufLen=0;bufLen<8;bufLen++) ptop.sin_zero[bufLen] = 0; SetNonblock( false ); */ m_bOpen = true; m_nPacketLen = 0; m_nCur = 0; } CUDPSocket::CUDPSocket(char *sOtherName,unsigned short nPort,bool bRaw) { CUDPSocket( inet_addr(sOtherName), nPort, bRaw ); } bool CUDPSocket::Listen(unsigned int nAllowConn) { return true; } unsigned int CUDPSocket::ReadBlock(char *sBuf,unsigned int nLen ) { if (!m_bOpen) return 0; unsigned int nRemain=nLen; char bufffer[MAX_UDP_PACKET_SIZE]; while (nRemain>0){ if (m_nCur>=m_nPacketLen){//需要读报 unsigned int nIpAddr; unsigned short nPort; if( (m_nPacketLen=ReadFrom(bufffer,MAX_UDP_PACKET_SIZE,nIpAddr,nPort))>0 ){ m_nCur=0; } else if( m_nPacketLen<=0 ){ DebugPrint( "ReadFrom error, Socket error=%d\n", GetLastError() ); } else{ return (nLen-nRemain); } } else{//从缓冲区中读取 unsigned int nReadLen=((m_nPacketLen-m_nCur)>=nRemain)?nRemain:(m_nPacketLen-m_nCur); memcpy(sBuf+(nLen-nRemain),bufffer+m_nCur,nReadLen); nRemain -= nReadLen; m_nCur += nReadLen; } } return (nLen-nRemain); } unsigned int CUDPSocket::ReadBlock(char *sBuf,unsigned int nLen, unsigned int &nIpAddr,unsigned short &nPort ) { if (!m_bOpen) return 0; unsigned int nRemain=nLen; char bufffer[MAX_UDP_PACKET_SIZE]; while (nRemain>0){ if (m_nCur>=m_nPacketLen){//需要读报 if ((m_nPacketLen=ReadFrom(bufffer,MAX_UDP_PACKET_SIZE,nIpAddr,nPort))) m_nCur=0; else return (nLen-nRemain); } else{//从缓冲区中读取 unsigned int nReadLen=((m_nPacketLen-m_nCur)>=nRemain)?nRemain:(m_nPacketLen-m_nCur); memcpy(sBuf+(nLen-nRemain),bufffer+m_nCur,nReadLen); nRemain -= nReadLen; m_nCur += nReadLen; } } return (nLen-nRemain); } unsigned int CUDPSocket::ReadFrom(char *sBuf, unsigned int nLen,unsigned int &nIpAddr,unsigned short &nPort) { if (!m_bOpen) return 0; sockaddr_in sockAddr; // SOCKADDR_IN addr; #ifdef __MACOSX__ UINT addrLen = sizeof(sockAddr); #else int addrLen = sizeof(struct sockaddr); #endif int nRead=::recvfrom(m_skt,sBuf,nLen,0,(struct sockaddr *)&sockAddr, (socklen_t*)&addrLen); if (nRead!=SOCKET_ERROR) { #ifdef _WIN32 nIpAddr = sockAddr.sin_addr.S_un.S_addr; #else nIpAddr = sockAddr.sin_addr.s_addr; #endif nPort = ntohs(sockAddr.sin_port); // DebugPrint("recvfrom %s:%d", inet_ntoa(sockAddr.sin_addr), nPort); } // DebugPrint( "UDP Receive %dbytes data.\n", nRead ); return nRead; } unsigned int CUDPSocket::Peek(char *sBuf, unsigned int nLen) { if (!m_bOpen) return 0; sockaddr_in sockAddr; #ifdef __MACOSX__ UINT addrLen = sizeof(sockAddr); #else int addrLen = sizeof(sockAddr); #endif int nRead=::recvfrom(m_skt,sBuf,nLen,MSG_PEEK,(struct sockaddr *)&sockAddr, (socklen_t*)&addrLen); return nRead; } unsigned int CUDPSocket::SendTo(char *sBuf,unsigned int nLen, unsigned int nIpAddr,unsigned short nPort ) { if (!m_bOpen) return 0; sockaddr_in sockAddr; memset(&sockAddr, 0, sizeof(sockAddr) ); sockAddr.sin_family=AF_INET; sockAddr.sin_addr.s_addr = nIpAddr; sockAddr.sin_port = htons(nPort); // DebugPrint("sendto %s:%d", inet_ntoa(sockAddr.sin_addr), nPort); int nWrite = ::sendto(m_skt, (const char *)sBuf, nLen, 0, (struct sockaddr *)&sockAddr, sizeof(sockaddr) ); if (nWrite!=SOCKET_ERROR){ return nWrite; } else{ int nError=GetLastError(); DebugPrint("CUDPSocket::Send,Socket error = %d\n",nError); return 0; } } unsigned int CUDPSocket::Send(char *sBuf,unsigned int nLen) { if (!m_bOpen) return 0; int nWrite = ::sendto(m_skt, (const char *)sBuf, nLen, 0, (struct sockaddr *)&ptop,sizeof(sockaddr)); if (nWrite!=SOCKET_ERROR){ return nWrite; } else{ int nError=GetLastError(); DebugPrint("PUDPSocket::Send,Socket error = %d\n",nError); return 0; } } // ////////////////////////////////////////////////////////////////////////// #define TCP_NODELAY 0x0001 ////////////////////////////////////////////////////////////////////////// // CTCPSocket // CTCPSocket::CTCPSocket() { if ((m_skt = socket (AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET){ DebugPrint("Can't open tcp socket\n"); return; } /* if( SetNonblock( true )!=0 ) return; */ int yes = 1; setsockopt( m_skt, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes) ); setsockopt( m_skt, SOL_SOCKET, SO_KEEPALIVE, (char *)&yes, sizeof(yes) ); setsockopt( m_skt, SOL_SOCKET, SO_REUSEADDR, (char *)0, 0 ); setsockopt( m_skt, SOL_SOCKET, SO_OOBINLINE, (char *)&yes, sizeof(yes) ); #ifdef SO_NOSIGPIPE #ifndef MSG_NOSIGNAL setsockopt( m_skt, SOL_SOCKET, SO_NOSIGPIPE, (char *)&yes, sizeof(yes) ); #endif #endif m_bOpen = true; } CTCPSocket::CTCPSocket(unsigned short nPort) { if ((m_skt = socket (AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET){ DebugPrint("Can't open tcp socket\n"); m_bOpen = false; return; } SOCKADDR_IN local_sin; local_sin.sin_family = AF_INET; local_sin.sin_port = htons (nPort); local_sin.sin_addr.s_addr = htonl(INADDR_ANY); if (bind (m_skt,(struct sockaddr *) &local_sin,sizeof (local_sin)) == SOCKET_ERROR){ DebugPrint("Binding Error\n"); // Close(); return; } m_bOpen = true; } CTCPSocket::CTCPSocket(char *sOtherName,unsigned short nPort) { if ((m_skt = socket (AF_INET,SOCK_STREAM,0)) == INVALID_SOCKET){ DebugPrint("Can't open tcp socket\n"); m_bOpen = false; return; } int yes = 1; setsockopt(m_skt, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes)); setsockopt(m_skt, SOL_SOCKET, SO_KEEPALIVE, (char *)&yes, sizeof(yes)); setsockopt (m_skt, SOL_SOCKET, SO_REUSEADDR, (char *)0, 0); setsockopt (m_skt, SOL_SOCKET, SO_OOBINLINE, (char *)&yes, sizeof(yes)); m_bOpen = Connect( inet_addr(sOtherName), nPort ); } bool CTCPSocket::Listen(unsigned int nAllowConn) { if (listen (m_skt,nAllowConn) == SOCKET_ERROR){ DebugPrint("Listening to the client failed.\n"); // Close(); return false; } return true; } bool CTCPSocket::Accept(CTCPSocket *pServerSkt) { sockaddr accept_sin; #ifdef __MACOSX__ UINT nAcptSinLen = sizeof (accept_sin); #else int nAcptSinLen = sizeof (accept_sin); #endif m_skt = accept(pServerSkt->GetSocket(), (struct sockaddr *)&accept_sin, (socklen_t*)&nAcptSinLen); if (m_skt == INVALID_SOCKET) { DebugPrint("Accepting connection with client failed\n"); return false; } m_bOpen = true; return true; } bool CTCPSocket::Connect(unsigned int nIpAddr,unsigned short nPort) { if( m_skt==-1 ) return false; SetNonblock( true ); SOCKADDR_IN dest_sin; dest_sin.sin_family = AF_INET; dest_sin.sin_port = htons (nPort); dest_sin.sin_addr.s_addr = nIpAddr; int nError = connect( m_skt,(PSOCKADDR)&dest_sin,sizeof (dest_sin)); if( nError==SOCKET_ERROR ){ nError = WSAGetLastError(); #ifdef _WIN32 if( nError!=WSAEWOULDBLOCK ){ #else if( nError!=EINPROGRESS ){ #endif DebugPrint("Connecting to the server connect error. code=%d\n", nError ); m_bOpen = false; // closesocket( m_skt ); // m_skt = -1; return false; } fd_set fdWr; FD_ZERO(&fdWr); FD_SET(m_skt,&fdWr); timeval tv; tv.tv_sec = 5;//等待5秒钟 tv.tv_usec = 0; nError = select(m_skt+1, NULL, &fdWr, NULL, &tv); if( nError==0 ){ DebugPrint("Connecting to the server time out.\n"); m_bOpen = false; return false; } else if( nError==SOCKET_ERROR || !FD_ISSET(m_skt, &fdWr) ){ nError = WSAGetLastError(); DebugPrint("Connecting to the server select error. code=%d\n", nError); m_bOpen = false; // closesocket( m_skt ); // m_skt = -1; return false; } else{ DebugPrint( "Connecting select return %d\n", nError ); } } else{ DebugPrint( "Tcp connect return %d\n", nError ); } SetNonblock( false ); return true; } unsigned int CTCPSocket::ReadBlock(char *sBuf,unsigned int nLen) { if (!m_bOpen) return 0; unsigned int nReturn = recv (m_skt, sBuf, nLen, 0); if( nReturn==0 ){ DebugPrint( "Socket has been shutdown by remote.\n" ); // Close(); return 0; } if( nReturn==SOCKET_ERROR ){ int err = WSAGetLastError(); DebugPrint("Socket error, code=%d\n", err); // Close(); return 0; } DebugPrint( "TCP Receive %dbytes data.\n", nReturn ); return nReturn; } unsigned int CTCPSocket::Send(char *sBuf,unsigned int nLen) { if (!m_bOpen) return 0; unsigned nReturn = send( m_skt, sBuf, nLen, 0 ); if (nReturn == SOCKET_ERROR){ int err = WSAGetLastError(); DebugPrint("Sending data to the client failed. err=%d\n", err); // Close(); return -1; } return nReturn; } void CTCPSocket::GetPeerAddr(char *sAddr) { sockaddr_in addr; #ifdef __MACOSX__ UINT size = sizeof(addr); #else int size = sizeof(addr); #endif if (getpeername(m_skt,(struct sockaddr *)&addr,(socklen_t*)&size)==SOCKET_ERROR) strcpy(sAddr,""); else{ char *pb=(char *)&(addr.sin_addr); unsigned b1=(unsigned char)(*pb); unsigned b2=(unsigned char)(*(pb+1)); unsigned b3=(unsigned char)(*(pb+2)); unsigned b4=(unsigned char)(*(pb+3)); sprintf(sAddr,"%d.%d.%d.%d",b1,b2,b3,b4); } } // //////////////////////////////////////////////////////////////////////////