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