📄 socket.cpp
字号:
#include <string.h>#ifndef __Win32__#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <sys/uio.h>#include <unistd.h>#include <netinet/tcp.h>#include <fcntl.h>#endif#include <errno.h>#include "OS.h"#include "Socket.h"#include "SocketUtils.h"#include "OSThread.h"#include "MyAssert.h"#ifdef USE_NETLOG#include <netlog.h>#endif#define INVALID_FD (-1)Socket::Socket(): fState(kBlockingSocketType),// fLocalAddrStrPtr(NULL),// fLocalDNSStrPtr(NULL), fPortStr(fPortBuffer, kPortBufSizeInBytes){ fFileDesc = INVALID_FD; fLocalAddr.sin_addr.s_addr = 0; fLocalAddr.sin_port = 0; fDestAddr.sin_addr.s_addr = 0; fDestAddr.sin_port = 0; }Socket::~Socket(){ Close();}void Socket::Initialize(){#ifdef __Win32__ // Start Win32 DLLs WORD wsVersion = MAKEWORD(1, 1); WSADATA wsData; (void)::WSAStartup(wsVersion, &wsData);#else#endif}void Socket::Uninitialize(){#ifdef __Win32__ WSACleanup();#else#endif}OS_Error Socket::Open(int theType){ Close(); if(fFileDesc == INVALID_FD) { fFileDesc = ::socket(PF_INET, theType, 0); if (fFileDesc == kInvalidFileDesc) { Int32 ErrNo = (OS_Error)OS::GetErrno(); return ErrNo; }#ifdef __Win32__ //set default send and receive buffer size SetSocketBufSize(32*1024); SetSocketRcvBufSize(32*1024);#endif } return OS_NoErr;}void Socket::Close(){ if(fFileDesc != INVALID_FD) {#ifdef __Win32__ ::closesocket(fFileDesc);#else //::shutdown(fFileDesc,SHUT_RDWR); ::close(fFileDesc);#endif fFileDesc = INVALID_FD; }}void Socket::ReuseAddr(){ int one = 1; int err = ::setsockopt(fFileDesc, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(int)); Assert(err == 0); }void Socket::NoDelay(){ int one = 1; int err = ::setsockopt(fFileDesc, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(int)); Assert(err == 0); }void Socket::KeepAlive(){ int one = 1; int err = ::setsockopt(fFileDesc, SOL_SOCKET, SO_KEEPALIVE, (char*)&one, sizeof(int)); Assert(err == 0); }void Socket::SetSocketBufSize(UInt32 inNewSize){ int bufSize = inNewSize; int err = ::setsockopt(fFileDesc, SOL_SOCKET, SO_SNDBUF, (char*)&bufSize, sizeof(int)); Assert(err == 0);}OS_Error Socket::SetSocketRcvBufSize(UInt32 inNewSize){ int bufSize = inNewSize; int err = ::setsockopt(fFileDesc, SOL_SOCKET, SO_RCVBUF, (char*)&bufSize, sizeof(int)); if (err == -1) return OS::GetErrno(); return OS_NoErr;}OS_Error Socket::Bind(UInt32 addr, UInt16 port){#ifndef USE_NETLOG#if defined(__Win32__) // missing from some platform includes typedef int socklen_t;#endif#endif socklen_t len = sizeof(fLocalAddr); ::memset(&fLocalAddr, 0, sizeof(fLocalAddr)); fLocalAddr.sin_family = AF_INET; fLocalAddr.sin_port = htons(port); fLocalAddr.sin_addr.s_addr = htonl(addr); int err = ::bind(fFileDesc, (sockaddr *)&fLocalAddr, sizeof(fLocalAddr)); if (err == -1) { fLocalAddr.sin_port = 0; fLocalAddr.sin_addr.s_addr = 0; return (OS_Error)OS::GetErrno(); } else
::getsockname(fFileDesc, (sockaddr *)&fLocalAddr, &len); // get the kernel to fill in unspecified values fState |= kBound; return OS_NoErr;}std::string Socket::GetLocalAddrStr(){ string strTmp; SocketUtils::ConvertAddrToString(fLocalAddr.sin_addr, &strTmp); return strTmp;}OS_Error Socket::Send(const char* inData, const UInt32 inLength, UInt32* outLengthSent,UInt32 vTimeOut){ Assert(inData != NULL); if (!(fState & kConnected)) return (OS_Error)ENOTCONN; //timout calc int err = 0; if(vTimeOut != 0) { struct timeval val; val.tv_sec = 0; val.tv_usec = vTimeOut * 1000; fd_set TmpSet; FD_ZERO(&TmpSet); FD_SET(fFileDesc,&TmpSet); err = select(fFileDesc+1, NULL,&TmpSet, NULL, &val); if(err <=0 ) { if(err == 0) err = EAGAIN; return err; } } //send do { err = ::send(fFileDesc, inData, inLength, 0);//flags?? } while((err == -1) && (OS::GetErrno() == EINTR)); if (err == -1) { //Are there any errors that can happen if the client is connected? //Yes... EAGAIN. Means the socket is now flow-controleld int theErr = OS::GetErrno(); if ((theErr != EAGAIN) && (this->IsConnected())) fState ^= kConnected;//turn off connected state flag return (OS_Error)theErr; } *outLengthSent = err; return OS_NoErr;}OS_Error Socket::WriteV(const struct iovec* iov, const UInt32 numIOvecs, UInt32* outLenSent,UInt32 vTimeOut){ Assert(iov != NULL); if (!(fState & kConnected)) return (OS_Error)ENOTCONN; //timout calc int err = 0; if(vTimeOut != 0) { struct timeval val; val.tv_sec = 0; val.tv_usec = vTimeOut * 1000; fd_set TmpSet; FD_ZERO(&TmpSet); FD_SET(fFileDesc,&TmpSet); err = select(fFileDesc+1, NULL,&TmpSet, NULL, &val); if(err <=0 ) { if(err == 0) err = EAGAIN; return err; } } do {#ifdef __Win32__ DWORD theBytesSent = 0; err = ::WSASend(fFileDesc, (LPWSABUF)iov, numIOvecs, &theBytesSent, 0, NULL, NULL); if (err == 0) err = theBytesSent;#else err = ::writev(fFileDesc, iov, numIOvecs);//flags??#endif } while((err == -1) && (OS::GetErrno() == EINTR)); if (err == -1) { // Are there any errors that can happen if the client is connected? // Yes... EAGAIN. Means the socket is now flow-controleld int theErr = OS::GetErrno(); if ((theErr != EAGAIN) && (this->IsConnected())) fState ^= kConnected;//turn off connected state flag return (OS_Error)theErr; } *outLenSent = (UInt32)err; return OS_NoErr;}OS_Error Socket::Peek(void *buffer, const UInt32 length, UInt32 *outRecvLenP){ Assert(outRecvLenP != NULL); Assert(buffer != NULL); if (!(fState & kConnected)) return (OS_Error)ENOTCONN; //int theRecvLen = ::recv(fFileDesc, buffer, length, 0);//flags?? int theRecvLen; do { theRecvLen = ::recv(fFileDesc, (char*)buffer, length, MSG_PEEK);//flags?? } while((theRecvLen == -1) && (OS::GetErrno() == EINTR)); if (theRecvLen == -1) { // Are there any errors that can happen if the client is connected? // Yes... EAGAIN. Means the socket is now flow-controleld int theErr = OS::GetErrno(); if ((theErr != EAGAIN ) && (this->IsConnected())) fState ^= kConnected;//turn off connected state flag return (OS_Error)theErr; } //if we get 0 bytes back from read, that means the client has disconnected. //Note that and return the proper error to the caller else if (theRecvLen == 0) { fState ^= kConnected; return (OS_Error)ENOTCONN; } Assert(theRecvLen > 0); *outRecvLenP = (UInt32)theRecvLen; return OS_NoErr;}OS_Error Socket::Read(void *buffer, const UInt32 length, UInt32 *outRecvLenP){ Assert(outRecvLenP != NULL); Assert(buffer != NULL); if (!(fState & kConnected)) return (OS_Error)ENOTCONN; //int theRecvLen = ::recv(fFileDesc, buffer, length, 0);//flags?? int theRecvLen; do { theRecvLen = ::recv(fFileDesc, (char*)buffer, length, 0);//flags?? } while((theRecvLen == -1) && (OS::GetErrno() == EINTR)); if (theRecvLen == -1) { // Are there any errors that can happen if the client is connected? // Yes... EAGAIN. Means the socket is now flow-controleld int theErr = OS::GetErrno(); if ((theErr != EAGAIN ) && (this->IsConnected())) fState ^= kConnected;//turn off connected state flag return (OS_Error)theErr; } //if we get 0 bytes back from read, that means the client has disconnected. //Note that and return the proper error to the caller else if (theRecvLen == 0) { fState ^= kConnected; return (OS_Error)ENOTCONN; } Assert(theRecvLen > 0); *outRecvLenP = (UInt32)theRecvLen; return OS_NoErr;}OS_Error Socket::SetNonBlocking(){#ifdef __Win32__ u_long one = 1; int err = ::ioctlsocket(fFileDesc, FIONBIO, &one);#else int flag = ::fcntl(fFileDesc, F_GETFL, 0); int err = ::fcntl(fFileDesc, F_SETFL, flag | O_NONBLOCK);#endif return err;}OS_Error Socket::SetBlocking(){#ifdef __Win32__ u_long one = 0; int err = ::ioctlsocket(fFileDesc, FIONBIO, &one);#else int flag = ::fcntl(fFileDesc, F_GETFL, 0); int err = ::fcntl(fFileDesc, F_SETFL, flag & ~O_NONBLOCK);#endif return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -