跨平台Socket封装——CTcpClient类

TcpClient.h

#ifndef __TCPSERVER_H__
#define __TCPSERVER_H__

namespace LinWin
{
    class CSocketImpl;
    class CSocketAddress;

    class CTcpClient
    {
    private:
        int m_SndTimeOut;
        int m_RcvTimeOut;
        CSocketImpl* m_sock;

    public:
        CTcpClient();
        CTcpClient(CSocketImpl* sock);
        ~CTcpClient();

        int Create(bool bAccept = false);
        void Close();
        int Connect(const CSocketAddress& addr);

        int SetSendTimeOut(int timeout);
        int SetRecvTimeOut(int timeout);
        int SetSendBufferSize(int size);
        int SetRecvBufferSize(int size);

        int Send(const void* lpBuf, unsigned int len);
        int Recv(void*lpBuf, unsigned int len);
        int Sendn(const void* lpBuf, unsigned int len);
        int Recvn(void*lpBuf, unsigned int len);
        int ReadLine(void*lpBuf, unsigned int len);

        net_socket_fd Sockfd() const;
        CSocketImpl* Handle();

    private:
        int RealSend(const void*lpBuf, unsigned int len);
        int RealRecv(void* lpBuf, unsigned int len);
    };
}

#endif

TcpClient.cpp类

#include "Platform.h"
#include "SocketImpl.h"
#include "TcpClient.h"

//
LinWin::CTcpClient::CTcpClient() : m_SndTimeOut(NET_INFINITE), m_RcvTimeOut(NET_INFINITE), m_sock(NULL)
{

}

LinWin::CTcpClient::CTcpClient(CSocketImpl* sock) : m_SndTimeOut(NET_INFINITE), m_RcvTimeOut(NET_INFINITE), m_sock(sock)
{

}

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

int LinWin::CTcpClient::Create(bool bAccept/* = false */)
{
    if (!m_sock)
    {
        m_sock = new CSocketImpl;
        if (!m_sock)
            return -1;
        if (!bAccept)
            return m_sock->Create();
    }

    return 0;
}

void LinWin::CTcpClient::Close()
{
    if (m_sock)
    {
        m_sock->Close();
        delete m_sock;
        m_sock = NULL;
    }
}

int LinWin::CTcpClient::Connect(const CSocketAddress& addr)
{
    if (Create() != 0)
        return -1;

    return m_sock->Connect(addr);
}

int LinWin::CTcpClient::SetSendTimeOut(int timeout)
{
    if (Create() != 0)
        return -1;

    if (timeout < 0)
        timeout = NET_INFINITE;

    m_SndTimeOut = timeout;

#ifdef WINDOWS_FAMILY
    return m_sock->SetRawOption(SOL_SOCKET, SO_SNDTIMEO, &m_SndTimeOut, sizeof(m_SndTimeOut));
#else
    struct timeval tv;
    tv.tv_sec = m_SndTimeOut / 1000;
    tv.tv_usec = m_SndTimeOut % 1000 * 1000;
    return m_sock->SetRawOption(SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));
#endif  
}

int LinWin::CTcpClient::SetRecvTimeOut(int timeout)
{
    if (Create() != 0)
        return -1;

    if (timeout < 0)
        timeout = NET_INFINITE;

    m_RcvTimeOut = timeout;

#ifdef WINDOWS_FAMILY
    return m_sock->SetRawOption(SOL_SOCKET, SO_RCVTIMEO, &m_RcvTimeOut, sizeof(m_RcvTimeOut));
#else
    struct timeval tv;
    tv.tv_sec = m_SndTimeOut / 1000;
    tv.tv_usec = m_SndTimeOut % 1000 * 1000;
    return m_sock->SetRawOption(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
#endif
}

int LinWin::CTcpClient::SetSendBufferSize(int size)
{
    if (Create() != 0)
        return -1;

    return m_sock->SetOption(SOL_SOCKET, SO_SNDBUF, size);
}

int LinWin::CTcpClient::SetRecvBufferSize(int size)
{
    if (Create() != 0)
        return -1;

    return m_sock->SetOption(SOL_SOCKET, SO_RCVBUF, size);
}

int LinWin::CTcpClient::Send(const void* lpBuf, unsigned int len)
{
    return RealSend(lpBuf, len);
}

int LinWin::CTcpClient::Recv(void* lpBuf, unsigned int len)
{
    return RealRecv(lpBuf, len);
}

int LinWin::CTcpClient::Sendn(const void* lpBuf, unsigned int len)
{
    unsigned int offset = 0;
    const char* ptr = reinterpret_cast<const char*>(lpBuf);
    int ret = NET_NO_ERROR;
    do
    {
        ret = RealSend(ptr, len - offset);
        if (ret != NET_SOCKET_ERROR)
        {
            offset += ret;
            ptr += ret;
        }
        else break;
    } while (offset < len);

    return ret;
}

int LinWin::CTcpClient::Recvn(void* lpBuf, unsigned int len)
{
    unsigned int offset = 0;
    char* ptr = reinterpret_cast<char*>(lpBuf);
    int ret = NET_NO_ERROR;
    do
    {
        ret = RealRecv(ptr, len - offset);

        if (ret != NET_SOCKET_ERROR)
        {
            if (ret == 0)
                break;
            offset += ret;
            ptr += ret;
        }
        else break;
    } while (offset < len);

    return ret;
}

int LinWin::CTcpClient::ReadLine(void*lpBuf, unsigned int len)
{
    memset(lpBuf, 0, len);
    char* ptr = reinterpret_cast<char*>(lpBuf);
    unsigned int offset = 0;
    int ret = NET_NO_ERROR;
    do
    {
        ret = RealRecv(ptr, 1);
        if (ret != 1)
            break;
        char ch = *ptr;
        if (ch == '\n')
            break;
        offset++;
        ptr++;
    } while (offset < len);

    if (offset == len)
        ret = -1;

    return offset;
}

int LinWin::CTcpClient::RealSend(const void*lpBuf, unsigned int lpLen)
{
    return m_sock->SendBytes(lpBuf, lpLen, 0);
}

int LinWin::CTcpClient::RealRecv(void* lpBuf, unsigned int lpLen)
{
    return m_sock->RecvBytes(lpBuf, lpLen);
}

net_socket_fd LinWin::CTcpClient::Sockfd() const
{
    return m_sock->Sockfd();
}

LinWin::CSocketImpl* LinWin::CTcpClient::Handle()
{
    return m_sock;
}

设置发送超时和接收超时,Windows下单位是毫秒ms,Linux下是秒s。此实现,统一为毫秒单位。
2016/12/12修改ReadLine的返回值为offset。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
说明: 1此程序由ecz00程序优化而来 地址 http://download.csdn.net/download/ecz00/9403630 因此程序可以说是网上唯一的tcpclient使用的中文案例,提供了我思路,在此感谢 ;为什么用这个插件,vb自带的插件winsock 这么有用的插件 居然不是微软自带的插件, 最要命的是 直接注册ocx控件 win7 win10上可能因为序列号无法注册,那么vb下如何开发ip客户端,变得很麻烦,尝试过APi方法的,但是过于复杂,程序量太大,比较麻烦,因此用 此方案比较可行,在原版的基础上花了5天时间摸索和优化, 此版本使用方法 1 把vbRichClient5.dll放进C:\Windows\SysWOW64 (64位系统) 2 在vb6中点击 工程->引用 把上面的dll引用进来就可以额,不需要注册 3:使用sscom5.12.1 或其他tcp调试软件软件启动tcpserver 地址是127,0,0,1 5676 4:直接运行本软件即可使用。点击连接,显示成功,说明连接成功,可以相互发送数据了 服务端的程序在原版上未做修改,请自行优化 此软件改进了原版 1:无法显示连接状态和错误信息 2:只能发送不能接收 3:使用主机名的连接方式,无法直接使用,一开始 4:无法显示byte值 5:界面修改 6:连接的时候,不断开以前的连接,造成重复连接 提示 vbRichClient5的手册找遍了都找不到,估计作者都没写,更别想有中文版了,所以只能 在vb6中点击视图-》对象窗口,可显示vbRichClient5.dll 所有的和方法 QQ175891641 2018-2-15优化
### 回答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、付费专栏及课程。

余额充值