TcpClient.h

#ifndef TCPCLIENT_H
#define TCPCLIENT_H

#define ERR_REUSEADDR	-14
#define TCP_SEND_FAIL   -1  //tcp发送失败
#define TCP_BIND_FAIL   -2  //tcp绑定失败
#define TCP_CONN_FAIL   -3  //tcp连接失败
#define TCP_ERROR_ATTR -4 //错误的参数
#define CONNECT_TIME_OUT_MIN 10000 //tcp连接超时最小时间(微秒)
#define CONNECT_TIME_OUT_MAX 250000 //tcp连接超时最大时间(微秒)
#define SYS_FD_BUFF_SZ 128000
#define USE_UNBLOCK 1   //

class TCPClient
{
public:
    TCPClient();

    ~TCPClient();

    //初始
    int init();

    //释放
    void destroy();

    //建立tcp连接
    int conn(const char *ip, unsigned short port,unsigned short localPort=0);

    //发送数据,0:正常,-1:失败,-2:连接失败
    int send(char *msg, int len);

    //接收数据
    int recv(char *msg, int maxlen, int ms);

    //关闭tcp连接
    int close();

    //获取sockfd
    int getSocketFD()const;

    //设置连接超时
    void setConnTimeout(int msecond);

    //获取本机ip和端口,0: 成功, 1: 失败
#ifdef __linux__
    int tcpGetLocalAddr(char *ip, unsigned short *port);
#endif

private:
    //增大缓冲区
    void increaseFdBuff();

private:
    //fd
    int mSockfd;

    //连接ip
    char mIP[16];

    //连接端口
    unsigned short mPort;

    //连接超时时间
    int mConnTimeout;
};


#endif // TCPCLIENT_H



TcpClient.cpp


#include "TcpClient.h"
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#ifndef __linux__
#include <WinSock.h>
#endif

TCPClient::TCPClient()
{
    mSockfd = -1;
    bzero(mIP,sizeof(mIP));
    mPort = 0;
    mConnTimeout = CONNECT_TIME_OUT_MIN;
    init();
}

TCPClient::~TCPClient()
{
    close();
    destroy();
}

/*
    初始化
*/
int TCPClient::init()
{
#ifndef __linux__
    int ret = 0;
    WSADATA wsaData;
    if ((ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
    {
        return -1;
    }
#endif
    return 0;
}

/*
    释放
*/
void TCPClient::destroy()
{
#ifndef __linux__
    WSACleanup();
#endif
}

/*
    建立tcp连接
*/
int TCPClient::conn(const char *ip, unsigned short port, unsigned short localPort)
{
    if(port<=0||strlen(ip)==0){
        return TCP_ERROR_ATTR;
    }
#ifdef __linux__
    strcpy(mIP, ip);
    mPort = port;

    if (mSockfd > 0){
        close();
    }

    if ((mSockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        return TCP_CONN_FAIL;
    }

    struct sockaddr_in addr;
    bzero(&addr,sizeof(addr));

    if(localPort>0)
    {
        addr.sin_family = AF_INET;
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        addr.sin_port = htons(localPort);
        //绑定客户端的地址信息,使得客户端的端口号固定
        if(bind(mSockfd,(struct sockaddr *)&addr,sizeof(addr))<0){
            return TCP_BIND_FAIL;
        }
    }

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(port);

#if USE_UNBLOCK
    timeval tm;
    fd_set set;
    unsigned long ul = 1;
    ioctl(mSockfd, FIONBIO, &ul); //设置为非阻塞模式
    int len = sizeof(int);
    bool ret = false;
    int error = -1;
    if( connect(mSockfd, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    {
        tm.tv_sec = 0;
        tm.tv_usec = mConnTimeout;
        FD_ZERO(&set);
        FD_SET(mSockfd, &set);
        if( select(mSockfd+1, NULL, &set, NULL, &tm) > 0)
        {
            getsockopt(mSockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
            if(error == 0){
                ret = true;
            }else{
                ret = false;
            }
        }else
        {
            ret = false;
        }
    }else{
        ret = true;
    }
    ul = 0;
    ioctl(mSockfd, FIONBIO, &ul); //设置为阻塞模式
    if(!ret)
    {
        close();
        return -1;
    }else
    {
        increaseFdBuff();
    }
#else

    if (connect (mSockfd, (struct sockaddr *) &addr, sizeof(addr)) < 0)
    {
        close();
        return -1;
    }
#endif
    return 0;
#else
    //windows version
    struct sockaddr_in addr;

    if ((m_sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("socket");
        return -1;
    }

    //设置非阻塞
    unsigned long u1 = 1;
    int ret = ioctlsocket(m_sockfd,FIONBIO,(unsigned long*)&u1);
    if(ret==SOCKET_ERROR){
        return -1;
    }

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(ip);
    addr.sin_port = htons(port);

    ret = connect (m_sockfd, (struct sockaddr *) &addr, sizeof(addr));

    struct timeval timeout;
    fd_set r;
    FD_ZERO(&r);
    FD_SET(m_sockfd,&r);
    timeout.tv_sec = 2;
    timeout.tv_usec = 500000;
    ret = select(0,0,&r,0,&timeout);
    if(ret<=0)
    {
        ::closesocket(m_sockfd);
        return 0;
    }

    //设置成非阻塞
    unsigned long ul1 = 0;
    ret = ioctlsocket(m_sockfd,FIONBIO,(unsigned long*)&ul1);
    if(ret==SOCKET_ERROR)
    {
        ::closesocket(m_sockfd);
        return -1;
    }


    return m_sockfd;
#endif
}


/*
    接收数据
*/
int TCPClient::recv(char *msg, int maxlen, int ms)
{
    if (mSockfd < 0)
    {
#ifdef __linux__
        usleep(ms * 1000);
#else
        Sleep(ms);
#endif
        return -99;
    }

    int ret = 0;
    timeval tv;
    if (ms > 0)
    {
        tv.tv_sec = ms / 1000;
        tv.tv_usec = (ms % 1000) * 1000;

        fd_set rset;
        FD_ZERO(&rset);
        FD_SET(mSockfd, &rset);
        ret = select(mSockfd + 1, &rset, NULL, NULL, &tv);
        if (ret == 0)
        {
            return -1;
        }
        else if (ret < 0)
        {
            return ret;
        }
        else
        {
            if(mSockfd<0){
                return -1;
            }
            if (! FD_ISSET(mSockfd, &rset)){
                return -1;
            }
        }
    }

#ifdef __linux__
    ret = read(mSockfd, msg, maxlen);
#else
    ret = recv(m_sockfd, msg, maxlen, 0);
#endif
    if (ret <= 0){
        close();
    }

    return ret;
}

/*
    发送数据,0:正常,-1:失败,-99:连接失败
*/
int TCPClient::send(char *msg, int len)
{
    int r = 0;

    if (mSockfd <= 0){
        if(conn(mIP, mPort) < 0){
            return TCP_CONN_FAIL;
        }
    }

    while (len > 0)
    {
#ifdef __linux__
        r = write(mSockfd, msg, len);
#else
        r = send(m_sockfd, msg, len, 0);
#endif
        if (r <= 0)
        {
            close();
            return TCP_SEND_FAIL;
        }
        msg +=  r;
        len -= r;
    }
    return 0;
}

/*
    关闭tcp连接
*/
int TCPClient::close()
{
    if (mSockfd > 0)
    {
#ifdef __linux__
        ::close(mSockfd);
#else
        closesocket (m_sockfd);
#endif
        mSockfd = -1;
    }
    return 0;
}

/*
    获取sockfd
*/
int TCPClient::getSocketFD()const
{
    return mSockfd;
}

/*
    设置连接超时
*/
void TCPClient::setConnTimeout(int msecond)
{
    if(msecond<CONNECT_TIME_OUT_MIN){
        mConnTimeout = CONNECT_TIME_OUT_MIN;
    }else if(msecond>CONNECT_TIME_OUT_MAX){
        mConnTimeout = CONNECT_TIME_OUT_MAX;
    }else{
        mConnTimeout = msecond;
    }
}

/*
    增大缓冲区
*/
void TCPClient::increaseFdBuff()
{
    int bufSize = SYS_FD_BUFF_SZ;
    setsockopt(mSockfd,SOL_SOCKET,SO_SNDBUF,&bufSize,sizeof(bufSize));
    setsockopt(mSockfd,SOL_SOCKET,SO_RCVBUF,&bufSize,sizeof(bufSize));
}

/*
    获取本机ip和端口,0: 成功, 1: 失败
*/
#ifdef __linux__
int TCPClient::tcpGetLocalAddr(char *ip, unsigned short *port)
{
    struct sockaddr_in addr;
    bzero(&addr,sizeof(addr));
    socklen_t len = sizeof(addr);
    if(! getsockname(mSockfd, (struct sockaddr *) (&addr), &len))
    {
        *port = (unsigned short) ntohs(addr.sin_port);
        if (inet_ntop(AF_INET, &(addr.sin_addr.s_addr), ip, INET_ADDRSTRLEN)){
            return 0;
        }
    }
    return -1;
}
#endif