//
|
// ClientSocket.h
|
// GoldRich
|
//
|
// Created by WindShan on 2017/3/8.
|
// Copyright © 2017年 WindShan. All rights reserved.
|
//
|
|
#ifndef ClientSocket_h
|
#define ClientSocket_h
|
|
#include <sys/socket.h>
|
#include <fcntl.h>
|
#include <errno.h>
|
#include <netinet/in.h>
|
#include <arpa/inet.h>
|
|
#define SOCKET unsigned int
|
#define SOCKET_ERROR -1
|
#define INVALID_SOCKET -1
|
|
#include "pthread.h"
|
#include "IClientSocket.h"
|
|
|
#define call_func_no_param(f) if(f != nullptr){f();}
|
#define call_func_one_param(f,p) if(f != nullptr){f(p);}
|
|
#include "NetStream.h"
|
|
#ifndef INADDR_NONE
|
#define INADDR_NONE 0xffffffff
|
#endif // !INADDR_NONE
|
|
enum connect_status
|
{
|
con_status_ing = 1,
|
con_status_suc = 0,
|
con_status_err = -1,
|
con_status_timeout = -2,
|
|
con_status_called_err = -100,
|
con_status_called_timeout = -101,
|
};
|
|
|
static int init_sock_reference = 0;
|
typedef struct __package
|
{
|
int size;
|
char* buf;
|
}send_package,rec_package;
|
|
|
class CClientSocket
|
{
|
public:
|
CClientSocket(void)
|
:success_call(nullptr),
|
timeout_call(nullptr),
|
error_call(nullptr),
|
receive_call(nullptr),
|
socket_handle(INVALID_SOCKET),
|
out_time(20),
|
ser_addr(0),
|
ser_port(0)
|
{
|
con_status = con_status_err;
|
|
def_recbuf_size = 64*1024;
|
def_sendbuf_size = 64*1024;
|
|
def_buf = new char[def_recbuf_size];
|
memset(def_buf,0,def_recbuf_size);
|
|
pRecStream = new CNetStream;
|
}
|
|
~CClientSocket(void)
|
{
|
success_call = nullptr;
|
error_call = nullptr;
|
timeout_call = nullptr;
|
receive_call = nullptr;
|
|
if (socket_handle != INVALID_SOCKET)
|
{
|
Close();
|
socket_handle = INVALID_SOCKET;
|
}
|
|
if (pRecStream)
|
{
|
pRecStream->detach();
|
delete pRecStream;
|
}
|
|
if (def_buf)
|
{
|
delete []def_buf;
|
def_buf = nullptr;
|
}
|
|
for (list<send_package>::iterator i = lst_send.begin();i != lst_send.end();i++)
|
{
|
ClosePkg(*i);
|
}
|
lst_send.clear();
|
}
|
public:
|
static int InitSockEnv()
|
{
|
init_sock_reference++;
|
|
return 1;
|
}
|
|
static void UninitSockEnv()
|
{
|
init_sock_reference--;
|
}
|
public:
|
int Connect(const char* ip,short port,int outTime,on_connect_success sc,on_connect_time_out tm,on_connect_error er,on_receive_package re)
|
{
|
|
Clear();
|
|
success_call = sc;
|
timeout_call = tm;
|
error_call = er;
|
receive_call = re;
|
|
ser_addr = inet_addr(ip);
|
ser_port = port;
|
out_time = outTime;
|
if (ip == 0 || strlen(ip) > 15 || ser_addr == INADDR_NONE)
|
{
|
con_status = con_status_err;
|
call_func_no_param(error_call);
|
con_status = con_status_called_err;
|
return -1;
|
}
|
|
|
socket_handle = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
|
if (socket_handle == INVALID_SOCKET)
|
{
|
Close();
|
con_status = con_status_err;
|
call_func_no_param(error_call);
|
con_status = con_status_called_err;
|
|
return -1;
|
}
|
|
|
int nRes = 0;
|
#ifdef WIN32
|
unsigned long mod = 1;
|
nRes = ioctlsocket(socket_handle,FIONBIO,&mod);
|
#else
|
// 设置为非阻塞方式
|
nRes = fcntl(socket_handle,F_SETFL,O_NONBLOCK);
|
#endif
|
|
if (nRes < 0 )
|
{
|
Close();
|
con_status = con_status_err;
|
call_func_no_param(error_call);
|
con_status = con_status_called_err;
|
|
return -1;
|
}
|
|
con_status = con_status_ing;
|
pthread_create(&t_id,nullptr,connect_thread_func,this);
|
|
|
return 1;
|
}
|
int SendStream(CNetStream* pStream)
|
{
|
if (pStream == nullptr){
|
return -1;
|
}
|
|
return CreateNewPkg(pStream->getLenth(),pStream->getData());
|
}
|
int Close()
|
{
|
return close(m_sockClient);
|
}
|
|
|
//you should call this function in circle
|
void process()
|
{
|
DoReceive();
|
|
CheckErr();
|
|
switch (con_status)
|
{
|
case con_status_suc:
|
{
|
Flush();
|
break;
|
}
|
case con_status_err:
|
{
|
call_func_no_param(error_call);
|
con_status = con_status_called_err;
|
break;
|
}
|
case con_status_called_err:
|
break;
|
case con_status_ing:
|
break;
|
case con_status_timeout:
|
break;
|
case con_status_called_timeout:
|
break;
|
|
default:
|
break;
|
}
|
|
}
|
|
private:
|
int GetError()
|
{
|
int err = 0;
|
#ifdef WIN32
|
err = WSAGetLastError();
|
if(err != WSAEWOULDBLOCK) {
|
#else
|
err = errno;
|
if(err != EINPROGRESS && err != EAGAIN)
|
{
|
#endif
|
return 1;
|
}
|
|
return 0;
|
}
|
|
int DoConnectProcess()
|
{
|
sockaddr_in addr_in;
|
memset((void*)&addr_in,0,sizeof(addr_in));
|
|
addr_in.sin_family = AF_INET;
|
addr_in.sin_port = htons(ser_port);
|
addr_in.sin_addr.s_addr = ser_addr;
|
|
if (connect(socket_handle,(sockaddr*)&addr_in,sizeof(addr_in)) == SOCKET_ERROR)
|
{
|
if (GetError() == 1)
|
{
|
Close();
|
con_status = con_status_err;
|
/*call_func_no_param(error_call);
|
con_status = con_status_called_err;*/
|
|
return -1;
|
}
|
|
timeval timeout;
|
timeout.tv_sec = out_time;
|
timeout.tv_usec = 0;
|
fd_set writeset,exceptset;
|
FD_ZERO(&writeset);
|
FD_ZERO(&exceptset);
|
FD_SET(socket_handle,&writeset);
|
FD_SET(socket_handle,&exceptset);
|
|
int ret = select(FD_SETSIZE,nullptr,&writeset,&exceptset,&timeout);
|
if (ret < 0)
|
{
|
Close();
|
con_status = con_status_err;
|
/*call_func_no_param(error_call);
|
con_status = con_status_called_err;*/
|
|
return -1;
|
}
|
else if (ret == 0)
|
{
|
Close();
|
con_status = con_status_timeout;
|
call_func_no_param(timeout_call);
|
con_status = con_status_called_timeout;
|
}
|
|
ret = FD_ISSET(socket_handle,&exceptset);
|
if(ret){
|
Close();
|
con_status = con_status_err;
|
/*call_func_no_param(error_call);
|
con_status = con_status_called_err;*/
|
|
return -1;
|
}
|
}
|
|
struct linger so_linger;
|
so_linger.l_onoff = 1;
|
so_linger.l_linger = 5;
|
|
setsockopt(socket_handle,SOL_SOCKET,SO_LINGER,(const char*)&so_linger,sizeof(so_linger));
|
setsockopt(socket_handle,SOL_SOCKET,SO_RCVBUF,(const char*)&def_recbuf_size,sizeof(int));
|
setsockopt(socket_handle,SOL_SOCKET,SO_SNDBUF,(const char*)&def_sendbuf_size,sizeof(int));
|
|
con_status = con_status_suc;
|
call_func_no_param(success_call);
|
|
|
return 1;
|
}
|
static void* connect_thread_func(void* arg)
|
{
|
CClientSocket* pObj = (CClientSocket*)arg;
|
if (pObj != nullptr)
|
{
|
pObj->DoConnectProcess();
|
}
|
|
return 0;
|
}
|
|
int CheckErr()
|
{
|
if (con_status == con_status_ing){
|
return -1;
|
}
|
|
if (con_status == con_status_called_err || con_status == con_status_called_timeout){
|
con_status = con_status_called_err;
|
return -1;
|
}
|
|
if (socket_handle == INVALID_SOCKET || con_status == con_status_err){
|
con_status = con_status_err;
|
return -1;
|
}
|
|
char buf[1];
|
int nRet = recv(socket_handle,buf,1,MSG_PEEK);
|
if(nRet == 0)
|
{
|
Close();
|
con_status = con_status_err;
|
|
return -1;
|
}
|
else if(nRet < 0)
|
{
|
if (GetError() == 1)
|
{
|
Close();
|
con_status = con_status_err;
|
|
return -1;
|
}
|
}
|
|
con_status = con_status_suc;
|
|
return 1;
|
}
|
|
int CreateNewPkg(int size,const char* buf)
|
{
|
if (size > 0 && buf != nullptr)
|
{
|
send_package pkg;
|
pkg.size = size;
|
pkg.buf = new char[size];
|
memcpy(pkg.buf,buf,pkg.size);
|
lst_send.push_back(pkg);
|
|
return 1;
|
}
|
|
return -1;
|
}
|
|
int ClosePkg(send_package& pkg)
|
{
|
if (pkg.buf)
|
{
|
delete []pkg.buf;
|
pkg.buf = nullptr;
|
pkg.size = 0;
|
return 1;
|
}
|
|
return -1;
|
}
|
|
int Flush()
|
{
|
if (lst_send.size() > 0) // have send data
|
{
|
list<send_package>::iterator iPkg = lst_send.begin();
|
int sd_size = send(socket_handle,iPkg->buf,iPkg->size,0);
|
if (sd_size >= iPkg->size)
|
{
|
ClosePkg(*iPkg);
|
lst_send.pop_front();
|
return 1;
|
}
|
else
|
{
|
printf("send err ,data is to larage!>>>>>>");
|
return -1;
|
}
|
}
|
|
return 1;
|
}
|
|
int DoReceive()
|
{
|
|
if(con_status != con_status_suc) { return -1; }
|
|
int rec_size = recv(socket_handle,def_buf,def_recbuf_size,0);
|
|
if (rec_size > 0 )
|
{
|
pRecStream->attach(def_buf,def_recbuf_size,rec_size);
|
call_func_one_param(receive_call,pRecStream);
|
pRecStream->detach();
|
|
return 1;
|
}
|
else if (rec_size == 0)
|
{
|
Close();
|
con_status = con_status_err;
|
|
return -1;
|
}
|
else
|
{
|
if (GetError() == 1)
|
{
|
Close();
|
return -1;
|
}
|
}
|
|
return 1;
|
}
|
|
void Clear()
|
{
|
if (socket_handle != INVALID_SOCKET){
|
Close();
|
socket_handle = INVALID_SOCKET;
|
}
|
|
success_call = nullptr;
|
error_call = nullptr;
|
timeout_call = nullptr;
|
receive_call = nullptr;
|
|
ser_addr = 0;
|
ser_port = 0;
|
out_time = 20;
|
|
if (def_buf != nullptr){
|
memset(def_buf,0,def_recbuf_size);
|
}
|
|
con_status = con_status_err;
|
|
for (list<send_package>::iterator i = lst_send.begin();i != lst_send.end();i++)
|
{
|
ClosePkg(*i);
|
}
|
lst_send.clear();
|
}
|
|
|
private://member data
|
on_connect_success success_call;
|
on_connect_time_out timeout_call;
|
on_connect_error error_call;
|
on_receive_package receive_call;
|
|
SOCKET socket_handle;
|
|
unsigned long ser_addr;
|
short ser_port;
|
unsigned long out_time;
|
|
int con_status;
|
|
int def_recbuf_size;
|
int def_sendbuf_size;
|
|
char* def_buf;
|
CNetStream* pRecStream;
|
|
list<send_package> lst_send;
|
list<rec_package> lst_rec;
|
|
|
|
|
pthread_t t_id;
|
pthread_t rec_tid;
|
};
|
|
#endif /* ClientSocket_h */
|