Marine Library  1.0
C++ library for Linux Networking Development
sockets.hh
1 #ifndef DOZERG_SOCKETS_H_20080229
2 #define DOZERG_SOCKETS_H_20080229
3 
4 /*
5  对网络socket的简单包装,隐藏了IPv4和IPv6协议相关性 ISocket 网络socket基类 CUdpSocket udp socket CListenSocket tcp服务器端监听socket CTcpConnSocket tcp客户端socket //*/ #include "file.hh" #include "sock_addr.hh" NS_SERVER_BEGIN class ISocket : public IFileDesc { protected: //目前支持的socket类型 enum EType{kTcp, kUdp}; CSockAddr peer_; //opt peer addr public: ISocket(){} //获取本端地址 CSockAddr hostAddr() const{ CSockAddr addr; if(valid()){ struct sockaddr_storage sa; socklen_t len = sizeof sa; ::memset(&sa, 0, len); if(0 == ::getsockname(fd(), reinterpret_cast<struct sockaddr *>(&sa), &len)) addr.setAddr(sa, len); } return addr; } //获取对端地址 const CSockAddr & peerAddr() const{return peer_;} //设置close()时是否等待数据发送 //on: // false timeout的值被忽略,等于内核缺省情况,close()会立即返回,如果可能将会传输任何未发送的数据 // true: // timeout==0 close()时连接夭折,丢弃发送缓冲区的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,能避免TIME_WAIT状态 // timeout!=0 close()时如果发送缓冲区中仍残留数据,进程将处于睡眠状态,直到 // (a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0) // (b)延迟时间到,此时close()将返回EWOULDBLOCK错误,且发送缓冲区中的任何数据都丢失 //timeoutS: 等待时间,Linux下单位为秒 //return: // true 设置成功 // false 设置失败 bool linger(bool on, int timeoutS = 0){ struct linger ling; ling.l_onoff = (on ? 1 : 0); ling.l_linger = timeoutS; return setOpt(SO_LINGER, ling); } //设置端口释放后是否可以立即再次使用 bool reuseAddr(bool on){ int flag = (on ? 1 : 0); return setOpt(SO_REUSEADDR, flag); } //设置/获取接收超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool recvTimeout(int timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_RCVTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int recvTimeout() const{ struct timeval tv; if(!getOpt(SO_RCVTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取发送超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool sendTimeout(uint32_t timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_SNDTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int sendTimeout() const{ struct timeval tv; if(!getOpt(SO_SNDTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取接收缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool recvBufSize(int size){ if(size < 0) return false; return setOpt(SO_RCVBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
6  ISocket 网络socket基类 CUdpSocket udp socket CListenSocket tcp服务器端监听socket CTcpConnSocket tcp客户端socket //*/ #include "file.hh" #include "sock_addr.hh" NS_SERVER_BEGIN class ISocket : public IFileDesc { protected: //目前支持的socket类型 enum EType{kTcp, kUdp}; CSockAddr peer_; //opt peer addr public: ISocket(){} //获取本端地址 CSockAddr hostAddr() const{ CSockAddr addr; if(valid()){ struct sockaddr_storage sa; socklen_t len = sizeof sa; ::memset(&sa, 0, len); if(0 == ::getsockname(fd(), reinterpret_cast<struct sockaddr *>(&sa), &len)) addr.setAddr(sa, len); } return addr; } //获取对端地址 const CSockAddr & peerAddr() const{return peer_;} //设置close()时是否等待数据发送 //on: // false timeout的值被忽略,等于内核缺省情况,close()会立即返回,如果可能将会传输任何未发送的数据 // true: // timeout==0 close()时连接夭折,丢弃发送缓冲区的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,能避免TIME_WAIT状态 // timeout!=0 close()时如果发送缓冲区中仍残留数据,进程将处于睡眠状态,直到 // (a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0) // (b)延迟时间到,此时close()将返回EWOULDBLOCK错误,且发送缓冲区中的任何数据都丢失 //timeoutS: 等待时间,Linux下单位为秒 //return: // true 设置成功 // false 设置失败 bool linger(bool on, int timeoutS = 0){ struct linger ling; ling.l_onoff = (on ? 1 : 0); ling.l_linger = timeoutS; return setOpt(SO_LINGER, ling); } //设置端口释放后是否可以立即再次使用 bool reuseAddr(bool on){ int flag = (on ? 1 : 0); return setOpt(SO_REUSEADDR, flag); } //设置/获取接收超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool recvTimeout(int timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_RCVTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int recvTimeout() const{ struct timeval tv; if(!getOpt(SO_RCVTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取发送超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool sendTimeout(uint32_t timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_SNDTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int sendTimeout() const{ struct timeval tv; if(!getOpt(SO_SNDTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取接收缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool recvBufSize(int size){ if(size < 0) return false; return setOpt(SO_RCVBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
7  CUdpSocket udp socket
8  CListenSocket tcp服务器端监听socket
9  CTcpConnSocket tcp客户端socket
10 //*/
11 
12 #include "file.hh"
13 #include "sock_addr.hh"
14 
15 NS_SERVER_BEGIN
16 
17 class ISocket : public IFileDesc
18 {
19 protected:
20  //目前支持的socket类型
21  enum EType{kTcp, kUdp};
22  CSockAddr peer_; //opt peer addr
23 public:
24  ISocket(){}
25  //获取本端地址
26  CSockAddr hostAddr() const{
27  CSockAddr addr;
28  if(valid()){
29  struct sockaddr_storage sa;
30  socklen_t len = sizeof sa;
31  ::memset(&sa, 0, len);
32  if(0 == ::getsockname(fd(), reinterpret_cast<struct sockaddr *>(&sa), &len))
33  addr.setAddr(sa, len);
34  }
35  return addr;
36  }
37  //获取对端地址
38  const CSockAddr & peerAddr() const{return peer_;}
39  //设置close()时是否等待数据发送
40  //on:
41  // false timeout的值被忽略,等于内核缺省情况,close()会立即返回,如果可能将会传输任何未发送的数据 // true: // timeout==0 close()时连接夭折,丢弃发送缓冲区的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,能避免TIME_WAIT状态 // timeout!=0 close()时如果发送缓冲区中仍残留数据,进程将处于睡眠状态,直到 // (a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0) // (b)延迟时间到,此时close()将返回EWOULDBLOCK错误,且发送缓冲区中的任何数据都丢失 //timeoutS: 等待时间,Linux下单位为秒 //return: // true 设置成功 // false 设置失败 bool linger(bool on, int timeoutS = 0){ struct linger ling; ling.l_onoff = (on ? 1 : 0); ling.l_linger = timeoutS; return setOpt(SO_LINGER, ling); } //设置端口释放后是否可以立即再次使用 bool reuseAddr(bool on){ int flag = (on ? 1 : 0); return setOpt(SO_REUSEADDR, flag); } //设置/获取接收超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool recvTimeout(int timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_RCVTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int recvTimeout() const{ struct timeval tv; if(!getOpt(SO_RCVTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取发送超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool sendTimeout(uint32_t timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_SNDTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int sendTimeout() const{ struct timeval tv; if(!getOpt(SO_SNDTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取接收缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool recvBufSize(int size){ if(size < 0) return false; return setOpt(SO_RCVBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
42  // true:
43  // timeout==0 close()时连接夭折,丢弃发送缓冲区的任何数据并发送一个RST给对方,而不是通常的四分组终止序列,能避免TIME_WAIT状态
44  // timeout!=0 close()时如果发送缓冲区中仍残留数据,进程将处于睡眠状态,直到
45  // (a)所有数据发送完且被对方确认,之后进行正常的终止序列(描述字访问计数为0)
46  // (b)延迟时间到,此时close()将返回EWOULDBLOCK错误,且发送缓冲区中的任何数据都丢失
47  //timeoutS: 等待时间,Linux下单位为秒
48  //return:
49  // true 设置成功
50  // false 设置失败 bool linger(bool on, int timeoutS = 0){ struct linger ling; ling.l_onoff = (on ? 1 : 0); ling.l_linger = timeoutS; return setOpt(SO_LINGER, ling); } //设置端口释放后是否可以立即再次使用 bool reuseAddr(bool on){ int flag = (on ? 1 : 0); return setOpt(SO_REUSEADDR, flag); } //设置/获取接收超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool recvTimeout(int timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_RCVTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int recvTimeout() const{ struct timeval tv; if(!getOpt(SO_RCVTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取发送超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool sendTimeout(uint32_t timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_SNDTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int sendTimeout() const{ struct timeval tv; if(!getOpt(SO_SNDTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取接收缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool recvBufSize(int size){ if(size < 0) return false; return setOpt(SO_RCVBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
51  bool linger(bool on, int timeoutS = 0){
52  struct linger ling;
53  ling.l_onoff = (on ? 1 : 0);
54  ling.l_linger = timeoutS;
55  return setOpt(SO_LINGER, ling);
56  }
57  //设置端口释放后是否可以立即再次使用
58  bool reuseAddr(bool on){
59  int flag = (on ? 1 : 0);
60  return setOpt(SO_REUSEADDR, flag);
61  }
62  //设置/获取接收超时,仅对阻塞方式有效
63  //timeMs: 超时时间,单位毫秒;0为永不超时
64  bool recvTimeout(int timeMs){
65  if(timeMs < 0)
66  return false;
67  struct timeval tv;
68  tv.tv_sec = timeMs / 1000;
69  tv.tv_usec = timeMs % 1000 * 1000;
70  return setOpt(SO_RCVTIMEO, tv);
71  }
72  //return:
73  // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int recvTimeout() const{ struct timeval tv; if(!getOpt(SO_RCVTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取发送超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool sendTimeout(uint32_t timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_SNDTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int sendTimeout() const{ struct timeval tv; if(!getOpt(SO_SNDTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取接收缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool recvBufSize(int size){ if(size < 0) return false; return setOpt(SO_RCVBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
74  // 0 永不超时
75  // >0 超时时间,单位毫秒 int recvTimeout() const{ struct timeval tv; if(!getOpt(SO_RCVTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取发送超时,仅对阻塞方式有效 //timeMs: 超时时间,单位毫秒;0为永不超时 bool sendTimeout(uint32_t timeMs){ if(timeMs < 0) return false; struct timeval tv; tv.tv_sec = timeMs / 1000; tv.tv_usec = timeMs % 1000 * 1000; return setOpt(SO_SNDTIMEO, tv); } //return: // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int sendTimeout() const{ struct timeval tv; if(!getOpt(SO_SNDTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取接收缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool recvBufSize(int size){ if(size < 0) return false; return setOpt(SO_RCVBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
76  int recvTimeout() const{
77  struct timeval tv;
78  if(!getOpt(SO_RCVTIMEO, &tv))
79  return -1;
80  return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
81  }
82  //设置/获取发送超时,仅对阻塞方式有效
83  //timeMs: 超时时间,单位毫秒;0为永不超时
84  bool sendTimeout(uint32_t timeMs){
85  if(timeMs < 0)
86  return false;
87  struct timeval tv;
88  tv.tv_sec = timeMs / 1000;
89  tv.tv_usec = timeMs % 1000 * 1000;
90  return setOpt(SO_SNDTIMEO, tv);
91  }
92  //return:
93  // <0 出错 // 0 永不超时 // >0 超时时间,单位毫秒 int sendTimeout() const{ struct timeval tv; if(!getOpt(SO_SNDTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取接收缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool recvBufSize(int size){ if(size < 0) return false; return setOpt(SO_RCVBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
94  // 0 永不超时
95  // >0 超时时间,单位毫秒 int sendTimeout() const{ struct timeval tv; if(!getOpt(SO_SNDTIMEO, &tv)) return -1; return (tv.tv_sec * 1000 + tv.tv_usec / 1000); } //设置/获取接收缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool recvBufSize(int size){ if(size < 0) return false; return setOpt(SO_RCVBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
96  int sendTimeout() const{
97  struct timeval tv;
98  if(!getOpt(SO_SNDTIMEO, &tv))
99  return -1;
100  return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
101  }
102  //设置/获取接收缓冲区大小
103  //注意:
104  //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下:
105  // People regularly wonder whether the "*2" here
106  // is correct. Linux reserves half of the socket
107  // buffer for metadata (skbuff headers etc.)
108  // BSD doesn't do that. Most programs using
109  // SO_SNDBUF/SO_RCVBUF didn't expect this, because
110  // traditional BSD does not do metadata accounting,
111  // and on Linux they ended up with too small effective
112  // buffers. To fix this Linux always doubles the
113  // buffer internally to stay compatible.
114  // See also socket(7).
115  bool recvBufSize(int size){
116  if(size < 0)
117  return false;
118  return setOpt(SO_RCVBUF, size);
119  }
120  //return:
121  // <0 出错 // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
122  // >=0 接收缓冲区大小,单位字节 int recvBufSize() const{ int size; if(!getOpt(SO_RCVBUF, &size)) return -1; return size; } //设置/获取发送缓冲区大小 //注意: //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下: // People regularly wonder whether the "*2" here // is correct. Linux reserves half of the socket // buffer for metadata (skbuff headers etc.) // BSD doesn't do that. Most programs using // SO_SNDBUF/SO_RCVBUF didn't expect this, because // traditional BSD does not do metadata accounting, // and on Linux they ended up with too small effective // buffers. To fix this Linux always doubles the // buffer internally to stay compatible. // See also socket(7). bool sendBufSize(int size){ if(size < 0) return false; return setOpt(SO_SNDBUF, size); } //return: // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
123  int recvBufSize() const{
124  int size;
125  if(!getOpt(SO_RCVBUF, &size))
126  return -1;
127  return size;
128  }
129  //设置/获取发送缓冲区大小
130  //注意:
131  //Linux实际上会设置缓冲区大小为(2*size)字节,对此的解释如下:
132  // People regularly wonder whether the "*2" here
133  // is correct. Linux reserves half of the socket
134  // buffer for metadata (skbuff headers etc.)
135  // BSD doesn't do that. Most programs using
136  // SO_SNDBUF/SO_RCVBUF didn't expect this, because
137  // traditional BSD does not do metadata accounting,
138  // and on Linux they ended up with too small effective
139  // buffers. To fix this Linux always doubles the
140  // buffer internally to stay compatible.
141  // See also socket(7).
142  bool sendBufSize(int size){
143  if(size < 0)
144  return false;
145  return setOpt(SO_SNDBUF, size);
146  }
147  //return:
148  // <0 出错 // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
149  // >=0 接收缓冲区大小,单位字节 int sendBufSize() const{ int size; if(!getOpt(SO_SNDBUF, &size)) return -1; return size; } //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
150  int sendBufSize() const{
151  int size;
152  if(!getOpt(SO_SNDBUF, &size))
153  return -1;
154  return size;
155  }
156  //接收数据 //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
157  //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
158  //waitAll: 是否加MSG_WAITALL标志
159  //return:
160  // <0 失败 // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
161  // 0 对方关闭连接 // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
162  // >0 实际收到的数据大小,单位字节 ssize_t recvData(char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0)); } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
163  ssize_t recvData(char * buf, size_t sz, bool waitAll = false){
164  if(NULL == buf || !valid())
165  return -1;
166  return ::recv(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0));
167  }
168  //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; const size_t oldsz = buf.size(); buf.resize(oldsz + sz); const ssize_t ret = recvData(&buf[oldsz], sz, waitAll); if(ret <= 0) buf.resize(oldsz); else if(size_t(ret) < sz) buf.resize(oldsz + ret); return ret; } //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
169  template<class BufT>
170  ssize_t recvData(BufT & buf, size_t sz, bool waitAll = false){
171  if(!valid())
172  return -1;
173  const size_t oldsz = buf.size();
174  buf.resize(oldsz + sz);
175  const ssize_t ret = recvData(&buf[oldsz], sz, waitAll);
176  if(ret <= 0)
177  buf.resize(oldsz);
178  else if(size_t(ret) < sz)
179  buf.resize(oldsz + ret);
180  return ret;
181  }
182  //发送数据 //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
183  //return:
184  // <0 失败 // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
185  // >=0 实际发送的数据大小,单位字节 ssize_t sendData(const char * buf, size_t sz){ if(!valid()) return -1; if(NULL == buf || 0 == sz) return 0; return ::send(fd(), buf, sz, MSG_NOSIGNAL); } template<class BufT> ssize_t sendData(const BufT & buf){ if(buf.empty()) return 0; return sendData(&buf[0], buf.size()); } //内部状态描述,主要用于log std::string toString() const{ CToString oss; oss<<"{IFileDesc="<<IFileDesc::toString() <<", host="<<hostAddr().toString() <<", peer="<<peerAddr().toString() <<"}"; return oss.str(); } protected: //初始化 //family: 协议族(AF_INET/AF_INET6等) ISocket(int family, EType type){ getSock(family, type); } bool getSock(int family, EType type){ if(valid()) return false; //不允许重复初始化 if(AF_INET6 == family) //not supported family = AF_INET; switch(type){ case kTcp: fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP); break; case kUdp: fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP); break; default: return false; } return valid(); } bool bindTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen())); return false; } bool connectTo(const CSockAddr & addr){ if(valid() && addr.valid()) return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen()) || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
186  ssize_t sendData(const char * buf, size_t sz){
187  if(!valid())
188  return -1;
189  if(NULL == buf || 0 == sz)
190  return 0;
191  return ::send(fd(), buf, sz, MSG_NOSIGNAL);
192  }
193  template<class BufT>
194  ssize_t sendData(const BufT & buf){
195  if(buf.empty())
196  return 0;
197  return sendData(&buf[0], buf.size());
198  }
199  //内部状态描述,主要用于log
200  std::string toString() const{
201  CToString oss;
202  oss<<"{IFileDesc="<<IFileDesc::toString()
203  <<", host="<<hostAddr().toString()
204  <<", peer="<<peerAddr().toString()
205  <<"}";
206  return oss.str();
207  }
208 protected:
209  //初始化
210  //family: 协议族(AF_INET/AF_INET6等)
211  ISocket(int family, EType type){
212  getSock(family, type);
213  }
214  bool getSock(int family, EType type){
215  if(valid())
216  return false; //不允许重复初始化
217  if(AF_INET6 == family) //not supported
218  family = AF_INET;
219  switch(type){
220  case kTcp:
221  fd_ = ::socket(family, SOCK_STREAM, IPPROTO_TCP);
222  break;
223  case kUdp:
224  fd_ = ::socket(family, SOCK_DGRAM, IPPROTO_UDP);
225  break;
226  default:
227  return false;
228  }
229  return valid();
230  }
231  bool bindTo(const CSockAddr & addr){
232  if(valid() && addr.valid())
233  return (0 == ::bind(fd(), addr.sockaddr(), addr.socklen()));
234  return false;
235  }
236  bool connectTo(const CSockAddr & addr){
237  if(valid() && addr.valid())
238  return (0 == ::connect(fd(), addr.sockaddr(), addr.socklen())
239  || EINPROGRESS == errno); //非阻塞下,需要等待 return false; } private: template<class T> bool setOpt(int name, const T & v){ return (valid() && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v)); } template<class T> bool getOpt(int name, T * v) const{ assert(v); socklen_t len = sizeof(T); return (valid() && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len)); } }; class CUdpSocket : public ISocket { public: static const int kFdType = 4; CUdpSocket(){} //初始化 //family: 协议族(AF_INET/AF_INET6等) explicit CUdpSocket(int family) : ISocket(family, kUdp) {} bool getSock(int family){return ISocket::getSock(family, kUdp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
240  return false;
241  }
242 private:
243  template<class T>
244  bool setOpt(int name, const T & v){
245  return (valid()
246  && 0 == ::setsockopt(fd(), SOL_SOCKET, name, &v, sizeof v));
247  }
248  template<class T>
249  bool getOpt(int name, T * v) const{
250  assert(v);
251  socklen_t len = sizeof(T);
252  return (valid()
253  && 0 == ::getsockopt(fd(), SOL_SOCKET, name, v, &len));
254  }
255 };
256 
257 class CUdpSocket : public ISocket
258 {
259 public:
260  static const int kFdType = 4;
261  CUdpSocket(){}
262  //初始化
263  //family: 协议族(AF_INET/AF_INET6等)
264  explicit CUdpSocket(int family)
265  : ISocket(family, kUdp)
266  {}
267  bool getSock(int family){return ISocket::getSock(family, kUdp);}
268  //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CUdpSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //设置对端地址,可以多次调用设置不同地址 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
269  int fdType() const{return kFdType;}
270  const char * fdTypeName() const{return "CUdpSocket";}
271  //设置本端地址
272  bool bindAddr(const CSockAddr & addr){
273  if(!addr.valid())
274  return false;
275  if(!valid() && !getSock(addr.family()))
276  return false;
277  return bindTo(addr);
278  }
279  //设置对端地址,可以多次调用设置不同地址
280  bool connectAddr(const CSockAddr & addr){
281  if(!addr.valid())
282  return false;
283  if(!valid() && !getSock(addr.family()))
284  return false;
285  if(!connectTo(addr))
286  return false;
287  peer_ = addr;
288  return true;
289  }
290  //接收数据 //from: 返回对端地址,如果不需要,请调用ISocket::recvData //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
291  //from: 返回对端地址,如果不需要,请调用ISocket::recvData
292  //sz: 期望收到的数据大小,单位字节 //waitAll: 是否加MSG_WAITALL标志 //return: // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
293  //waitAll: 是否加MSG_WAITALL标志
294  //return:
295  // <0 失败 // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
296  // >=0 实际收到的数据大小,单位字节 using ISocket::recvData; ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){ if(NULL == buf || !valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len); if(ret >= 0) from.setAddr(addr, len); return ret; } //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
297  using ISocket::recvData;
298  ssize_t recvData(CSockAddr & from, char * buf, size_t sz, bool waitAll = false){
299  if(NULL == buf || !valid())
300  return -1;
301  struct sockaddr_storage addr;
302  socklen_t len = sizeof addr;
303  ::memset(&addr, 0, len);
304  ssize_t ret = ::recvfrom(fd(), buf, sz, (waitAll ? MSG_WAITALL : 0), reinterpret_cast<sockaddr *>(&addr), &len);
305  if(ret >= 0)
306  from.setAddr(addr, len);
307  return ret;
308  }
309  //收到的数据会追加到buf后面 template<class BufT> ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){ if(!valid()) return -1; struct sockaddr_storage addr; socklen_t len = sizeof addr; ::memset(&addr, 0, len); size_t oldsz = buf.size(); buf.resize(oldsz + sz); ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll); if(ret >= 0){ from.setAddr(addr, len); if(size_t(ret) < sz) buf.resize(oldsz + ret); }else buf.resize(oldsz); return ret; } //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
310  template<class BufT>
311  ssize_t recvData(CSockAddr & from, BufT & buf, size_t sz, bool waitAll = false){
312  if(!valid())
313  return -1;
314  struct sockaddr_storage addr;
315  socklen_t len = sizeof addr;
316  ::memset(&addr, 0, len);
317  size_t oldsz = buf.size();
318  buf.resize(oldsz + sz);
319  ssize_t ret = recvData(from, &buf[oldsz], sz, waitAll);
320  if(ret >= 0){
321  from.setAddr(addr, len);
322  if(size_t(ret) < sz)
323  buf.resize(oldsz + ret);
324  }else
325  buf.resize(oldsz);
326  return ret;
327  }
328  //发送数据 //to: 指定对端地址,如果无效,则调用ISocket::sendData //return: // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
329  //to: 指定对端地址,如果无效,则调用ISocket::sendData
330  //return:
331  // <0 失败 // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
332  // >=0 实际发送的数据大小,单位字节 using ISocket::sendData; ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){ if(!valid() || NULL == buf) return -1; if(!sz) return 0; if(!to.valid()) return ISocket::sendData(buf, sz); return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen()); } template<class BufT> ssize_t sendData(const CSockAddr & to, const BufT & buf){ if(buf.empty()) return 0; return sendData(to, &buf[0], buf.size()); } }; class CListenSocket; class CTcpConnSocket : public ISocket { friend class CListenSocket; public: static const int kFdType = 2; //初始化 //family: 协议族(AF_INET/AF_INET6等) CTcpConnSocket(){} explicit CTcpConnSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
333  using ISocket::sendData;
334  ssize_t sendData(const CSockAddr & to, const char * buf, size_t sz){
335  if(!valid() || NULL == buf)
336  return -1;
337  if(!sz)
338  return 0;
339  if(!to.valid())
340  return ISocket::sendData(buf, sz);
341  return ::sendto(fd(), buf, sz, MSG_NOSIGNAL, to.sockaddr(),to.socklen());
342  }
343  template<class BufT>
344  ssize_t sendData(const CSockAddr & to, const BufT & buf){
345  if(buf.empty())
346  return 0;
347  return sendData(to, &buf[0], buf.size());
348  }
349 };
350 
351 class CListenSocket;
352 
353 class CTcpConnSocket : public ISocket
354 {
355  friend class CListenSocket;
356 public:
357  static const int kFdType = 2;
358  //初始化
359  //family: 协议族(AF_INET/AF_INET6等)
360  CTcpConnSocket(){}
361  explicit CTcpConnSocket(int family)
362  : ISocket(family, kTcp)
363  {}
364  bool getSock(int family){return ISocket::getSock(family, kTcp);}
365  //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CTcpConnSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool connectAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; if(!connectTo(addr)) return false; peer_ = addr; return true; } //断开已有连接,重新连接服务器 //注意:非阻塞模式下,返回true不一定连接成功 bool reconnect(){ CSockAddr peer = peerAddr(); if(!peer.valid()) return false; if(valid()) this->close(); return (getSock(peer.family()) && connectTo(peer)); } }; class CListenSocket : public ISocket { public: static const int kQueueDefault = 1024; static const int kFdType = 3; //初始化 //family: 协议族(AF_INET/AF_INET6等) CListenSocket(){} explicit CListenSocket(int family) : ISocket(family, kTcp) {} bool getSock(int family){return ISocket::getSock(family, kTcp);} //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
366  int fdType() const{return kFdType;}
367  const char * fdTypeName() const{return "CTcpConnSocket";}
368  //设置本端地址
369  bool bindAddr(const CSockAddr & addr){
370  if(!addr.valid())
371  return false;
372  if(!valid() && !getSock(addr.family()))
373  return false;
374  return bindTo(addr);
375  }
376  //连接服务器
377  //注意:非阻塞模式下,返回true不一定连接成功
378  bool connectAddr(const CSockAddr & addr){
379  if(!addr.valid())
380  return false;
381  if(!valid() && !getSock(addr.family()))
382  return false;
383  if(!connectTo(addr))
384  return false;
385  peer_ = addr;
386  return true;
387  }
388  //断开已有连接,重新连接服务器
389  //注意:非阻塞模式下,返回true不一定连接成功
390  bool reconnect(){
391  CSockAddr peer = peerAddr();
392  if(!peer.valid())
393  return false;
394  if(valid())
395  this->close();
396  return (getSock(peer.family())
397  && connectTo(peer));
398  }
399 };
400 
401 class CListenSocket : public ISocket
402 {
403 public:
404  static const int kQueueDefault = 1024;
405  static const int kFdType = 3;
406  //初始化
407  //family: 协议族(AF_INET/AF_INET6等)
408  CListenSocket(){}
409  explicit CListenSocket(int family)
410  : ISocket(family, kTcp)
411  {}
412  bool getSock(int family){return ISocket::getSock(family, kTcp);}
413  //返回fd类型和名称 int fdType() const{return kFdType;} const char * fdTypeName() const{return "CListenSocket";} //设置本端地址 bool bindAddr(const CSockAddr & addr){ if(!addr.valid()) return false; if(!valid() && !getSock(addr.family())) return false; return bindTo(addr); } //监听指定地址 //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
414  int fdType() const{return kFdType;}
415  const char * fdTypeName() const{return "CListenSocket";}
416  //设置本端地址
417  bool bindAddr(const CSockAddr & addr){
418  if(!addr.valid())
419  return false;
420  if(!valid() && !getSock(addr.family()))
421  return false;
422  return bindTo(addr);
423  }
424  //监听指定地址
425  //queueSz: 等待队列的最大长度 // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
426  // <=0 使用默认长度 // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
427  // 其他 指定长度 //block: // true 阻塞方式 // false 非阻塞方式 bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){ if(!addr.valid()) return false; if(!valid() && !bindAddr(addr)) return false; reuseAddr(true); if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } bool listenAddr(const CSockAddr & addr, int queueSz, bool block){ if(!addr.valid()) return false; if(!valid() && (!getSock(addr.family()) || !bindTo(addr))) return false; reuseAddr(true); if(!this->block(block)) return false; if(queueSz <= 0) queueSz = kQueueDefault; return (0 == ::listen(fd(), queueSz)); } //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
428  //block:
429  // true 阻塞方式
430  // false 非阻塞方式
431  bool listenAddr(const CSockAddr & addr, int queueSz = kQueueDefault){
432  if(!addr.valid())
433  return false;
434  if(!valid() && !bindAddr(addr))
435  return false;
436  reuseAddr(true);
437  if(queueSz <= 0)
438  queueSz = kQueueDefault;
439  return (0 == ::listen(fd(), queueSz));
440  }
441  bool listenAddr(const CSockAddr & addr, int queueSz, bool block){
442  if(!addr.valid())
443  return false;
444  if(!valid() && (!getSock(addr.family()) || !bindTo(addr)))
445  return false;
446  reuseAddr(true);
447  if(!this->block(block))
448  return false;
449  if(queueSz <= 0)
450  queueSz = kQueueDefault;
451  return (0 == ::listen(fd(), queueSz));
452  }
453  //接受远程连接 //sock: 返回已连接的socket bool acceptSocket(CTcpConnSocket & sock) const{ if(sock.valid() || !valid()) return false; struct sockaddr_storage ss; socklen_t len = sizeof ss; sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len); if(sock.valid()) sock.peer_.setAddr(ss, len); return (sock.valid() || EINTR == errno || EAGAIN == errno || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
454  //sock: 返回已连接的socket
455  bool acceptSocket(CTcpConnSocket & sock) const{
456  if(sock.valid() || !valid())
457  return false;
458  struct sockaddr_storage ss;
459  socklen_t len = sizeof ss;
460  sock.fd_ = ::accept(fd(), reinterpret_cast<struct sockaddr *>(&ss), &len);
461  if(sock.valid())
462  sock.peer_.setAddr(ss, len);
463  return (sock.valid()
464  || EINTR == errno
465  || EAGAIN == errno
466  || EWOULDBLOCK == errno); //非阻塞不作为错误 } }; NS_SERVER_END #endif
467  }
468 };
469 
470 NS_SERVER_END
471 
472 #endif
473 
virtual std::string toString() const
Get readable description of this object.
Definition: file.hh:163
bool valid() const
Test if this object is a valid file descriptor.
Definition: file.hh:65
std::string toString() const
Get readable description of this object.
Definition: sockets.hh:200
Abstract interface of fd (file descriptor).
Definition: file.hh:43
Definition: to_string.hh:43
const char * fdTypeName() const
Get type name of this object.
Definition: sockets.hh:415
Definition: sockets.hh:401
Encapsulation for fd (file descriptor) and regular files.
Definition: sock_addr.hh:24
void close()
Close this fd.
Definition: file.hh:153
int fdType() const
Get type id of this object.
Definition: sockets.hh:366
int fd() const
Get fd (file descriptor).
Definition: file.hh:70
Definition: sockets.hh:257
bool block(bool on)
Set block/non-block for operations.
Definition: file.hh:137
int fdType() const
Get type id of this object.
Definition: sockets.hh:414
Definition: sockets.hh:17
int fdType() const
Get type id of this object.
Definition: sockets.hh:269
const char * fdTypeName() const
Get type name of this object.
Definition: sockets.hh:270
const char * fdTypeName() const
Get type name of this object.
Definition: sockets.hh:367
Definition: sockets.hh:353