/****************************************************************************** * FILE: TcpTransport.cpp * Description: * Implementation of the CTcpTransport class. * * Modified Code History * Mark Date By Modification Reason ******************************************************************************* * 01 2007-10-8 songxw Initial creation. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "TcpTransport.h" CTcpTransport::CTcpTransport() : SockFd(-1) { memset(sTcpClientIpAddr, '\0', sizeof(sTcpClientIpAddr)); uTcpClientPort = 0; } CTcpTransport::CTcpTransport(char *pIpAddr, UINT16 port) : SockFd(-1) { strncpy2(sIpAddr, pIpAddr, 32); uPort = port; memset(sTcpClientIpAddr, '\0', sizeof(sTcpClientIpAddr)); uTcpClientPort = 0; } CTcpTransport::~CTcpTransport() { Close(); } int CTcpTransport::Create(TcpServiceType_E eType, char *pAddr, UINT16 port) { if((pAddr!= NULL) && (strlen(pAddr) > 0) && (port > 0)) { strncpy2(sIpAddr, pAddr, 32); uPort = port; } sType = eType; //Create the TCP socket SockFd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (-1 == SockFd) { perror("CTcpTransport socket"); return -1; } //Set Non-Blocking model //fcntl(SockFd, F_SETFL, O_NDELAY); // O_NONBLOCK //Create Tcp server or client if (TCP_SERVER == sType) { return Listen(); } else { if((strlen(sTcpClientIpAddr) > 0) && (uTcpClientPort > 0)) { //----------------------------------°ó¶¨Ô´IPºÍ¶Ë¿Ú--------------- struct sockaddr_in MyAddr; bzero(&MyAddr, sizeof(struct sockaddr_in) ); MyAddr.sin_family = AF_INET; MyAddr.sin_addr.s_addr = inet_addr(sTcpClientIpAddr); MyAddr.sin_port = htons(uTcpClientPort); if (bind(SockFd,(struct sockaddr *)&MyAddr, sizeof(struct sockaddr_in) ) == -1) { printf("%s socket bind %s %d\r\n",__FUNCTION__,sTcpClientIpAddr,uTcpClientPort); perror("bind"); } //-------------------------------------------------------------------- } return Connect(); } return 0; } int CTcpTransport::Close() { if (SockFd != -1) { close(SockFd); SockFd = -1; } return 0; } int CTcpTransport::Listen(void) { struct sockaddr_in MyAddr; struct linger linger; int optval; bzero(&MyAddr, sizeof(struct sockaddr_in) ); MyAddr.sin_family = AF_INET; //MyAddr.sin_addr.s_addr = inet_addr(sIpAddr); MyAddr.sin_addr.s_addr = htonl(INADDR_ANY); MyAddr.sin_port = htons(uPort); linger.l_onoff = 1; linger.l_linger = 0; if (setsockopt(SockFd, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(struct linger) ) == -1) { close(SockFd); perror("CTcpTransport set tcp sockopt linger error"); return -1; } optval = 1; if (setsockopt(SockFd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval) ) == -1) { close(SockFd); perror("CTcpTransport set tcp sockopt reuse address error"); return -1; } if (bind(SockFd, (struct sockaddr *)&MyAddr, sizeof(struct sockaddr_in) ) == -1) { close(SockFd); perror("CTcpTransport tcp bind error"); return -1; } if (listen(SockFd, 20) == -1) { close(SockFd); return -1; } return 0; } int CTcpTransport::Connect(void) { struct sockaddr_in SvrAddr; bzero(&SvrAddr, sizeof(struct sockaddr_in) ); SvrAddr.sin_family = AF_INET; SvrAddr.sin_addr.s_addr = inet_addr(sIpAddr); SvrAddr.sin_port = htons(uPort); #if 0 //------------set O_NONBLOCK------------------------------ int nFlags = fcntl(SockFd, F_GETFL, 0); if(nFlags < 0) { perror("fcntl F_GETFL"); close(SockFd); return -1; } if(fcntl(SockFd, F_SETFL, nFlags | O_NONBLOCK) < 0) { perror("setting O_NONBLOCK"); close(SockFd); return -1; } //---------------------------------------------------------- #endif if (connect(SockFd, (struct sockaddr *)&SvrAddr, sizeof(struct sockaddr_in) ) < 0) { if(errno != EINPROGRESS) { perror("connect"); close(SockFd); return -1; } else { if(!ReadSelect(100*1000)) { perror("connect"); close(SockFd); return -1; } } } return 0; } bool CTcpTransport::ReadSelect(UINT32 timeout) { int res; struct timeval tv; fd_set wrset; int valopt; socklen_t sock_len; if (timeout == 0) { tv.tv_sec=tv.tv_usec=0; } else { tv.tv_sec = timeout / 1000000; tv.tv_usec = timeout % 1000000; } FD_ZERO(&wrset); FD_SET(SockFd, &wrset); res = select(SockFd + 1, NULL, &wrset, NULL, &tv); if (res > 0) { sock_len = sizeof(int); if(getsockopt(SockFd, SOL_SOCKET, SO_ERROR, (void *) (&valopt), &sock_len) == 0) { if(!valopt) return true; } } return false; } bool CTcpTransport::IsReadSelect(UINT32 timeout) { int res; struct timeval tv; fd_set rdset; if (timeout == 0) { tv.tv_sec=tv.tv_usec=0; } else { tv.tv_sec = timeout / 1000000; tv.tv_usec = timeout % 1000000; } FD_ZERO(&rdset); FD_SET(SockFd, &rdset); res = select(SockFd + 1, &rdset, NULL, NULL, &tv); if (res > 0) { if(FD_ISSET(SockFd,&rdset)) { return true; } } return false; } int CTcpTransport::Send(UINT8 *pBuf, int len) { #if defined(TCP_SUPPORT_TPKT) //TPKT 4 bytes pBuf[0] = 0x03; pBuf[1] = 0x00; *(UINT16 *)(pBuf+2) = htons( (UINT16)(len - TPKT_MAX_LEN) ); #endif UINT8* p = pBuf; int iRet = 0, WLen = 0; do { iRet = send(SockFd, p+WLen, (len - WLen), 0); if (iRet <= 0) //(-1 == ret) && (errno != EINTR) { perror("send falid"); return iRet; } WLen += iRet; } while (len > WLen); return WLen; } int CTcpTransport::Read(UINT8 *pBuf, int BufLen, int param) { int iRet = recv(SockFd, pBuf, BufLen, param); if (iRet <= 0) { return -1; } return iRet; } int CTcpTransport::ServerRead(UINT8 *pBuf, int BufLen, int param) { struct sockaddr_in pin; socklen_t address_size = sizeof(pin); int ConnFd = accept(SockFd, (struct sockaddr *)&pin, &address_size); int iRet = recv(ConnFd, pBuf, BufLen, param); if (iRet <= 0) { return -1; } close(ConnFd); return iRet; } int CTcpTransport::GetSockName(char *pIpAddr, UINT16 &port) { struct sockaddr_in addr; socklen_t len = sizeof(sockaddr_in); //get socket addr and port info if (getsockname(SockFd, (struct sockaddr *)&addr, &len) == -1) { perror("getsockname"); return -1; } //strncpy2(pIpAddr, (char *)inet_ntoa(addr.sin_addr), IPSTR_MAX_LEN); inet_ntop(AF_INET, (struct in_addr *)&addr.sin_addr, pIpAddr, 32); //ʹÓÃḬ̈߳²È«º¯Êý port = ntohs(addr.sin_port); return 0; }