学习python时发现,socket和SocketServer的方便快捷,于是研究了一下socket和SocketServer.py写了一下C++版本的。
陆续分享一下。
1. socket类socket_t
socket++.h
/* class socket_t
* Description
* Simulation to python socket class
* Author
* wfb
* Version
* 0.1.0
* 2010/7/25
*/
#ifndef __SOCKET_PLUS_H__
#define __SOCKET_PLUS_H__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace ss
{
// it's NOT defined in (JUST A MAGIC, don't know y)
const size_t UNIX_PATH_MAX = 108;
/* address_t
* host[string] for ipaddress in ip4, unix-domain in AF_UNIX (ip6 NOT SUPPOSED RIGHT NOW, it's easy to)
* port[ushort] invalid for AF_UNIX
*/
struct address_t
{
std::string host;
unsigned short port;
address_t():host(""), port(0){}
address_t(const std::string& h, unsigned short p) : host(h), port(p){}
address_t(const address_t& add) : host(add.host), port(add.port){}
};
/* class socket_t
* int create();
* int create_from(int fileno);
* int accept(socket_t& socket, address_t& address);
* int bind(address_t& address);
* int listen(int backlog=5);
* int connect(const address_t& address);
* int close();
* int setsockopt(int level, int optname, int optval);
* int getsockopt(int level, int optname, int& optval);
* int reuse_address(int on=1
* int linger(int timeout=5);
* int send();
* int recv();
* int sendto();
* int recvfrom();
* int setblocking(int on=1);
* int fileno()const{return m_fileno;}
* int last_errno()const;
* int makefile();
*/
class socket_t
{
public:
socket_t():m_fileno(-1), m_ref(NULL){}
socket_t(int family, int type, int proto)
: m_fileno(::socket(family, type, proto)), m_family(family), m_type(type), m_proto(proto), m_ref(new int(1))
{}
socket_t(int fileno, int* pref, int family, int type, int proto)
: m_fileno(fileno), m_family(family), m_type(type), m_proto(proto), m_ref(pref ? pref : new int(1))
{}
socket_t(socket_t& sock)
: m_fileno(sock.m_fileno), m_family(sock.m_family), m_type(sock.m_type), m_proto(sock.m_proto), m_ref(sock.m_ref)
{
ref();
}
socket_t& operator=(socket_t& sock);
~socket_t(){close();}
int create();
int create_from(int fileno);
int accept(socket_t& socket, address_t& address);
int bind(address_t& address);
int listen(int backlog=5);
int connect(const address_t& address);
int close();
int setsockopt(int level, int optname, int optval);
int getsockopt(int level, int optname, int& optval);
int reuse_address(int on=1){return setsockopt(SOL_SOCKET, SO_REUSEADDR, on);}
int linger(int timeout=5);
/* TODO
int send();
int recv();
int sendto();
int recvfrom();
*/
int setblocking(int on=1);
int fileno()const{return m_fileno;}
int last_errno()const{return m_errno;}
int makefile(){return 0;}
private:
int ref(){if(NULL==m_ref)return 0;return ++*m_ref;}
int dref(){if(NULL==m_ref)return 0;return --*m_ref;}
private:
int m_fileno;
int m_family;
int m_type;
int m_proto;
int m_errno;
int* m_ref;
};
} // namespace ss
#endif //__SOCKET_PLUS_H__
socket++.cpp
#include "socket++.h"
namespace ss
{
socket_t& socket_t::operator=(socket_t& sock)
{
if (this==&sock) return *this;
this->close();
m_family = sock.m_family;
m_type = sock.m_type;
m_proto = sock.m_proto;
m_fileno = sock.m_fileno;
m_ref = sock.m_ref;
ref();
return *this;
}
int socket_t::create_from(int fileno)
{
if (m_ref) return m_fileno;
m_fileno = fileno;
m_ref = new int(1);
return m_fileno;
}
int socket_t::close()
{
int ret = 0;
if (m_ref && dref()<=0)
{
delete m_ref;
m_ref = NULL;
ret = ::close(m_fileno);
m_fileno = -1;
}
return ret;
}
int socket_t::bind(address_t& address)
{
sockaddr_in addr_in;
sockaddr_un addr_un;
sockaddr* paddr = NULL;
socklen_t addrlen = 0;
if (AF_INET==m_family)
{
bzero(&addr_in, sizeof(addr_in));
addr_in.sin_port = ::htons(address.port);
addr_in.sin_family = m_family;
if ((::inet_pton(m_family, address.host.c_str(), &addr_in.sin_addr)<=0))
{
m_errno = errno;
return -1;
}
paddr = (sockaddr*)&addr_in;
addrlen = sizeof(addr_in);
}
else if (AF_UNIX==m_family)
{
bzero(&addr_un, sizeof(addr_un));
addr_un.sun_family = AF_UNIX;
strncpy(addr_un.sun_path, address.host.c_str(), std::min(UNIX_PATH_MAX-1, address.host.size()));
address.host = addr_un.sun_path;
paddr = (sockaddr*)&addr_un;
addrlen = sizeof(addr_un);
}
else // AF_INET6 NOT supported
{
return -1;
}
if (::bind(m_fileno, paddr, addrlen))
{
m_errno = errno;
return -1;
}
return 0;
}
int socket_t::listen(int backlog/*=5*/)
{
int ret = ::listen(m_fileno, backlog);
if (ret)
{
m_errno = errno;
}
return ret;
}
int socket_t::accept(socket_t& socket, address_t& address)
{
sockaddr_in addr_in;
sockaddr_un addr_un;
sockaddr* paddr = NULL;
socklen_t addrlen = 0;
if (AF_INET==m_family)
{
bzero(&addr_in, sizeof(addr_in));
paddr = (sockaddr*)&addr_in;
addrlen = sizeof(addr_in);
}
else if (AF_UNIX==m_family)
{
bzero(&addr_un, sizeof(addr_un));
paddr = (sockaddr*)&addr_un;
addrlen = sizeof(addr_un);
}
int fd = ::accept(m_fileno, paddr, &addrlen);
if (fd>0)
{
if (AF_INET==m_family)
{
address.host = std::string(::inet_ntoa(addr_in.sin_addr));
address.port = ::ntohs(addr_in.sin_port);
}
else if (AF_UNIX==m_family)
{
address.host = addr_un.sun_path;
}
else
{
return -1;
}
socket_t client_sock(fd, NULL, m_family, m_type, m_proto);
socket = client_sock;
}
return fd;
}
int socket_t::connect(const address_t& address)
{
sockaddr_in addr_in;
sockaddr_un addr_un;
sockaddr* paddr = NULL;
socklen_t addrlen = 0;
if (m_family==AF_INET||m_family==AF_INET6)
{
bzero(&addr_in, sizeof(addr_in));
addr_in.sin_port = ::htons(address.port);
addr_in.sin_family = m_family;
if ((::inet_pton(m_family, address.host.c_str(), &addr_in.sin_addr)<=0))
{
m_errno = errno;
return -1;
}
paddr = (sockaddr*)&addr_in;
addrlen = sizeof(addr_in);
}
else if (m_family==AF_UNIX)
{
bzero(&addr_un, sizeof(addr_un));
addr_un.sun_family = AF_UNIX;
strncpy(addr_un.sun_path, address.host.c_str(), std::min(UNIX_PATH_MAX-1, address.host.size()));
paddr = (sockaddr*)&addr_un;
addrlen = sizeof(addr_un);
}
else // AF_INET6 NOT supported
{
return -1;
}
if (::connect(m_fileno, paddr, addrlen))
{
m_errno = errno;
return -1;
}
return 0;
}
int socket_t::setsockopt(int level, int optname, int optval)
{
int ret = ::setsockopt(m_fileno, level, optname, &optval, sizeof(optval));
if (ret)
{
m_errno = errno;
}
return ret;
}
int socket_t::getsockopt(int level, int optname, int& optval)
{
socklen_t optlen = sizeof(optval);
int ret = ::getsockopt(m_fileno, level, optname, &optval, &optlen);
if (ret)
{
m_errno = errno;
}
return ret;
}
int socket_t::setblocking(int on/*=1*/)
{
int ret = 0;
int val = 0;
if ((val = ::fcntl(m_fileno, F_GETFL)) == -1 && errno)
{
m_errno = errno;
return -1;
}
switch (on)
{
case 0:
if (val & O_NONBLOCK)
{
ret = ::fcntl(m_fileno, F_SETFL, 0);
}
break;
default:
if (!(val & O_NONBLOCK))
{
ret = ::fcntl(m_fileno, F_SETFL, 1);
}
break;
}
if (ret)
{
m_errno = errno;
}
return ret;
}
int socket_t::linger(int timeout/*=5*/)
{
struct linger lg;
lg.l_onoff=timeout>0?1:0;
lg.l_linger=timeout;
int ret = ::setsockopt(m_fileno, SOL_SOCKET, SO_LINGER, &lg, sizeof(lg));
if (ret)
{
m_errno = errno;
}
return ret;
}
} //namespace ss