跨平台Socket封装——CSocketImpl类

头文件SocketImpl.h

namespace LinWin
{
    class CSocketImpl
    {
    private:
        net_socket_fd m_sock;
        bool          m_bBlocking;

    public:
        CSocketImpl();
        CSocketImpl(net_socket_fd sockfd);
        CSocketImpl(const CSocketImpl& iml);
        virtual ~CSocketImpl();

    public:
        virtual int Create(int af = AF_INET, int type = SOCK_STREAM, int proto = 0);

        virtual void Close();

        virtual int Bind(const CSocketAddress& address);

        virtual int Listen(int backlog = 64);

        virtual int Accept(CSocketImpl* connfd, CSocketAddress& clientAddr);

        virtual int Connect(const CSocketAddress& addr);

        virtual int SendBytes(const void* lpBuf, unsigned int lpLen, int flag = 0);
        virtual int RecvBytes(void* lpBuf, unsigned int lpLen, int flag = 0);

        virtual int SendBytesto(const void* lpBuf, unsigned int lpLen, const CSocketAddress& addr, int flag = 0);
        virtual int RecvBytesfrom(void* lpBuf, unsigned int lpLen, CSocketAddress& addr, int flag = 0);

        virtual int ShutdownReceive();
        virtual int ShutdownSend();
        virtual int Shutdown();

        virtual int SetSendBufferSize(int size);
        virtual int GetSendBufferSize(int& size);

        virtual int SetReceiveBufferSize(int size);
        virtual int GetReceiveBufferSize(int& size);

        virtual int LocalAddress(CSocketAddress& localAddr);
        virtual int RemoteAddress(CSocketAddress& remoteAddr);

        virtual int Available(int& result);

        int SetOption(int level, int option, int value);
        int SetOption(int level, int option, unsigned value);
        int SetOption(int level, int option, unsigned char value);
        virtual int SetRawOption(int level, int option, const void* value, int length);

        int GetOption(int level, int option, int& value);
        int GetOption(int level, int option, unsigned& value);
        int GetOption(int level, int option, unsigned char& value);
        virtual int GetRawOption(int level, int option, void* value, int length);

        int SetLinger(bool on, int seconds);
        int GetLinger(bool& on, int& seconds);

        int SetNoDelay(bool flag);
        int GetNoDelay(bool& flag);

        int SetKeepAlive(bool flag);
        int GetKeepAlive(bool& flag);

        int SetReuseAddress(bool flag);
        int GetReuseAddress(bool& flag);

        virtual int SetBlocking(bool flag);
        virtual bool GetBlocking() const;

        net_socket_fd Sockfd() const;
        const net_socket_fd* Handle() const
        {
            return reinterpret_cast<const net_socket_fd*>(&m_sock);
        }

        int SocketError();

        virtual int Ioctl(net_ioctl_request_t request, int& arg);
        virtual int Ioctl(net_ioctl_request_t request, void* arg);
    }
}

Socket网络编程最基本的操作都封装在这里了,随后再把扩展的加进来。net_socket_fd类型的定义是为了统一平台之间的差异,它的定义已在platform.h文件中更新(在之前博客中)。

SocketImpl.cpp文件

#include "SocketImpl.h"

LinWin::CSocketImpl::CSocketImpl() : m_sock(NET_INVALID_SOCKET), m_bBlocking(false)
{

}

LinWin::CSocketImpl::CSocketImpl(net_socket_fd sock) : m_sock(sock), m_bBlocking(false)
{

}

LinWin::CSocketImpl::CSocketImpl(const CSocketImpl& iml) : m_sock(iml.m_sock), m_bBlocking(iml.m_bBlocking)
{

}

LinWin::CSocketImpl::~CSocketImpl()
{
    Close();
}

int LinWin::CSocketImpl::Create(int af /* = AF_INET */, int type /* = SOCK_STREAM */, int proto /* = 0 */)
{
    m_sock = ::socket(af, type, proto);

    return m_sock == NET_INVALID_SOCKET ? -1 : 0;
}

void LinWin::CSocketImpl::Close()
{
    if (m_sock != NET_INVALID_SOCKET)
    {
        closesocket(m_sock);
        m_sock = NET_INVALID_SOCKET;
    }
}

int LinWin::CSocketImpl::Bind(const CSocketAddress& address)
{
    if (m_sock == NET_INVALID_SOCKET)
        return -2;

    if (::bind(m_sock, reinterpret_cast<const struct sockaddr *>(address.GetAddress()), address.AddressLength()) != 0)
        return -1;

    return 0;
}

int LinWin::CSocketImpl::Listen(int backlog /* = 64 */)
{
    if (m_sock == NET_INVALID_SOCKET)
        return -2;

    if (::listen(m_sock, backlog) != 0)
        return -1;

    return 0;
}

int LinWin::CSocketImpl::Accept(CSocketImpl* connfd, CSocketAddress& clientAddr)
{
    if (m_sock == NET_INVALID_SOCKET || connfd == NULL)
        return -2;

    socklen_t salen = clientAddr.AddressLength();
    connfd->m_sock = ::accept(m_sock, reinterpret_cast<struct sockaddr*>(clientAddr.GetAddress()), &salen);
    if (connfd->m_sock == NET_INVALID_SOCKET)
        return -1;

    return 0;
}

int LinWin::CSocketImpl::Connect(const CSocketAddress& addr)
{
    if (m_sock == NET_INVALID_SOCKET)
        return -2;

    if (::connect(m_sock, reinterpret_cast<const struct sockaddr *>(addr.GetAddress()), addr.AddressLength()) != 0)
        return -1;

    return 0;
}

int LinWin::CSocketImpl::SendBytes(const void* lpBuf, unsigned int lpLen, int flag)
{
    return ::send(m_sock, reinterpret_cast<const char*>(lpBuf), lpLen, flag);
}

int LinWin::CSocketImpl::RecvBytes(void* lpBuf, unsigned int lpLen, int flag)
{
    return ::recv(m_sock, reinterpret_cast<char*>(lpBuf), lpLen, flag);
}

int LinWin::CSocketImpl::SendBytesto(const void* lpBuf, unsigned int lpLen, const CSocketAddress& addr, int flag)
{
    return ::sendto(m_sock, reinterpret_cast<const char*>(lpBuf), lpLen, flag,
        reinterpret_cast<const struct sockaddr*>(addr.GetAddress()), addr.AddressLength());
}

int LinWin::CSocketImpl::RecvBytesfrom(void* lpBuf, unsigned int lpLen, CSocketAddress& addr, int flag)
{
    socklen_t addrLen = addr.AddressLength();
    return ::recvfrom(m_sock, reinterpret_cast<char*>(lpBuf), lpLen, flag, 
        reinterpret_cast<sockaddr*>(addr.GetAddress()), &addrLen);
}

int LinWin::CSocketImpl::ShutdownReceive()
{
    return (::shutdown(m_sock, SD_RECEIVE) != 0) ? -1 : 0;
}

int LinWin::CSocketImpl::ShutdownSend()
{   
    return (::shutdown(m_sock, SD_SEND) != 0) ? -1 : 0;
}

int LinWin::CSocketImpl::Shutdown()
{
    return (::shutdown(m_sock, SD_BOTH) != 0) ? -1 : 0;
}

int LinWin::CSocketImpl::SetSendBufferSize(int size)
{
    return SetOption(SOL_SOCKET, SO_SNDBUF, size);
}

int LinWin::CSocketImpl::GetSendBufferSize(int& size)
{
    return GetOption(SOL_SOCKET, SO_SNDBUF, size);
}

int LinWin::CSocketImpl::SetReceiveBufferSize(int size)
{
    return SetOption(SOL_SOCKET, SO_RCVBUF, size);
}

int LinWin::CSocketImpl::GetReceiveBufferSize(int& size)
{
    return GetOption(SOL_SOCKET, SO_RCVBUF, size);
}

int LinWin::CSocketImpl::LocalAddress(CSocketAddress& localAddr)
{
    socklen_t saLen = sizeof(struct sockaddr_in);
    int rc = ::getsockname(m_sock, reinterpret_cast<struct sockaddr*>(localAddr.GetAddress()), &saLen);

    return rc != 0 ? -1 : 0;
}

int LinWin::CSocketImpl::RemoteAddress(CSocketAddress& remoteAddr)
{
    socklen_t saLen = sizeof(struct sockaddr_in);
    int rc = ::getpeername(m_sock, reinterpret_cast<struct sockaddr*>(remoteAddr.GetAddress()), &saLen);

    return rc != 0 ? -1 : 0;
}

int LinWin::CSocketImpl::Available(int& result)
{
    return Ioctl(FIONREAD, result);
}

int LinWin::CSocketImpl::SetOption(int level, int option, int value)
{
    return SetRawOption(level, option, &value, sizeof(value));
}

int LinWin::CSocketImpl::SetOption(int level, int option, unsigned value)
{
    return SetRawOption(level, option, &value, sizeof(value));
}

int LinWin::CSocketImpl::SetOption(int level, int option, unsigned char value)
{
    return SetRawOption(level, option, &value, sizeof(value));
}

int LinWin::CSocketImpl::SetRawOption(int level, int option, const void* value, int length)
{
    int rc = ::setsockopt(m_sock, level, option, reinterpret_cast<const char*>(value), (socklen_t)length);

    return rc == -1 ? -1 : 0;
}

int LinWin::CSocketImpl::GetOption(int level, int option, int& value)
{
    return GetRawOption(level, option, &value, sizeof(value));
}

int LinWin::CSocketImpl::GetOption(int level, int option, unsigned& value)
{
    return GetRawOption(level, option, &value, sizeof(value));
}

int LinWin::CSocketImpl::GetOption(int level, int option, unsigned char& value)
{
    return GetRawOption(level, option, &value, sizeof(value));
}

int LinWin::CSocketImpl::GetRawOption(int level, int option, void* value, int length)
{
    int rc = ::getsockopt(m_sock, level, option, reinterpret_cast<char*>(value), reinterpret_cast<socklen_t*>(&length));

    return rc == -1 ? -1 : 0;
}

int LinWin::CSocketImpl::SetLinger(bool on, int seconds)
{
    struct linger l;
    l.l_onoff = on ? 1 : 0;
    l.l_linger = seconds;
    return SetRawOption(SOL_SOCKET, SO_LINGER, &l, sizeof(l));
}

int LinWin::CSocketImpl::GetLinger(bool& on, int& seconds)
{
    struct linger l;
    int len = sizeof(l);
    int ret = GetRawOption(SOL_SOCKET, SO_LINGER, &l, len);
    if (ret == 0)
    {
        on = (l.l_onoff != 0);
        seconds = l.l_linger;
    }

    return ret;
}

int LinWin::CSocketImpl::SetNoDelay(bool flag)
{
    int value = flag ? 1 : 0;
    return SetOption(IPPROTO_TCP, TCP_NODELAY, value);
}

int LinWin::CSocketImpl::GetNoDelay(bool& flag)
{
    int value = 0;
    int ret = GetOption(IPPROTO_TCP, TCP_NODELAY, value);
    if (ret == 0)
        flag = (value != 0);

    return ret;
}

int LinWin::CSocketImpl::SetKeepAlive(bool flag)
{
    int value = flag ? 1 : 0;
    return SetOption(SOL_SOCKET, SO_KEEPALIVE, value);
}

int LinWin::CSocketImpl::GetKeepAlive(bool& flag)
{
    int value(0);
    int ret = GetOption(SOL_SOCKET, SO_KEEPALIVE, value);
    if (ret == 0)
        flag = (value != 0);

    return ret;
}

int LinWin::CSocketImpl::SetReuseAddress(bool flag)
{
    int value = flag ? 1 : 0;
    return SetOption(SOL_SOCKET, SO_REUSEADDR, value);
}

int LinWin::CSocketImpl::GetReuseAddress(bool& flag)
{
    int value(0);
    int ret = GetOption(SOL_SOCKET, SO_REUSEADDR, value);
    if (ret == 0)
        flag = (value != 0);

    return ret;
}

int LinWin::CSocketImpl::SetBlocking(bool flag)
{
#ifdef WINDOWS_FAMILY
    unsigned long nonblocking = flag ? 1 : 0;
    if (ioctlsocket(m_sock, FIONBIO, (unsigned long*)&nonblocking) == SOCKET_ERROR)
        return -1;
#else
    int opts;
    opts = fcntl(m_sock, F_GETFL);
    if (opts < 0)
        return -1;
    if (flag)
        opts = opts | O_NONBLOCK;
    else
        opts = opts & (~O_NONBLOCK);
    if (fcntl(m_sock, F_SETFL, opts) < 0)
        return -1;
#endif
    m_bBlocking = flag;

    return 0;
}

bool LinWin::CSocketImpl::GetBlocking() const
{
    return m_bBlocking;
}

net_socket_fd LinWin::CSocketImpl::Sockfd() const
{
    return m_sock;
}

int LinWin::CSocketImpl::Ioctl(net_ioctl_request_t request, int& arg)
{
    int rc;
#ifdef WINDOWS_FAMILY
    rc = ioctlsocket(m_sock, request, reinterpret_cast<u_long*>(&arg));
#else
    rc = ::ioctl(m_sock, request, &arg);
#endif

    return (rc != 0) ? -1 : 0;
}

int LinWin::CSocketImpl::Ioctl(net_ioctl_request_t request, void* arg)
{
    int rc;
#ifdef WINDOWS_FAMILY
    rc = ioctlsocket(m_sock, request, reinterpret_cast<u_long*>(arg));
#else
    rc = ::ioctl(m_sock, request, arg);
#endif

    return (rc != 0) ? -1 : 0;
}

int LinWin::CSocketImpl::SocketError()
{
#ifdef WINDOWS_FAMILY
    return GetLastError();
#else
    return errno;
#endif
}

由于CSocketAddress类中添加了一个非const版本的GetAddress成员函数,所以去掉此类中所有const_cast的转换。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 跨平台socket封装是指为了在不同操作系统或者硬件平台上运行的应用程序之间进行网络通信,将socket API进行封装,提供统一的接口来使得应用程序可以方便地进行网络通信。由于在不同操作系统或者硬件平台上,socket API的实现方式有所不同,因此需要对不同平台进行适配和封装跨平台socket封装的目的是方便开发人员进行网络通信,同时提高应用程序的可移植性、兼容性和可扩展性。在跨平台socket封装中,可以使用一些开源的第三方库,比如Boost.Asio、libevent等。这些第三方库提供了一些封装接口,使得应用程序能够使用统一的方式来进行网络编程。 在使用跨平台socket封装时,需要注意以下几点: 1.不同操作系统之间可能存在差异,需要进行相应的适配和兼容性测试。 2.在进行网络通信时,要保证通信协议的一致性,避免数据传输出现丢包或者粘包等问题。 3.要充分理解每个函数的含义和参数,以保证网络编程的正确性和可靠性。 总之,跨平台socket封装为应用程序提供了简单、方便、可移植的网络编程方式,是现代网络通信的重要组成部分。 ### 回答2: 跨平台socket封装是一种将不同操作系统的socket细节进行封装的技术。通过跨平台socket封装,我们可以让不同操作系统的socket代码在不进行修改的情况下在不同的平台上运行。这样可以加快开发者的开发速度,同时降低代码维护难度。 跨平台socket封装技术的实现需要解决两个问题:一是不同操作系统对socket函数的实现细节不同,导致代码实现难度大,需要针对每个操作系统单独编写代码;二是跨平台socket封装技术需要充分考虑移植性问题,需要确保在不同操作系统和硬件平台上稳定运行。 为了解决这些问题,跨平台socket封装技术通常采用C或C++语言编写,使用平台无关的API,例如POSIX API或者Winsock API。同时,跨平台socket封装也需要具备跨平台的编译和构建环境,例如常用的Cmake或者Autotools。 跨平台socket封装的好处是显而易见的,它不仅可以提高开发者的效率,还可以降低代码维护的难度。但是需要注意的是,跨平台socket封装并不是万能的,它需要根据实际应用场景进行选择。如果仅仅是针对特定平台开发应用,使用原生的socket API可能更加简单有效。但是在开发跨平台应用或者框架时,使用跨平台socket封装技术是非常重要的。 ### 回答3: 跨平台socket封装是一种将底层的socket通信接口进行封装,使得在不同的操作系统以及开发语言中实现socket通信更加简单和便捷的工具。封装后的跨平台socket可以隐藏底层操作系统的差异性,以统一的接口供用户使用,提高了代码的可复用性和跨平台移植性。 跨平台socket封装可以通过使用库的方式进行实现,例如常见的Socket.io和Boost.asio库等。这些库提供了高层次的API,使得开发者不再需要关注不同平台和语言下socket通信的实现细节,而是可以直接调用封装好的API进行开发。同时,这些库也提供了众多的工具和函数,能够帮助开发者更加便捷的进行socket通信的开发和调试。 跨平台socket封装的优点不仅在于提高编程效率,还可以提高系统的灵活性和可扩展性。开发者可以更加方便地进行平台切换和升级,同时还可以通过简单的调用来实现多个设备之间的通信。 总之,跨平台socket封装的出现大大方便了软件开发工作,能够满足当今多样化、交互性强的移动互联网市场需求,为开发者提供了高效、可靠的网络通信解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值