// // ClientSocket.h // GoldRich // // Created by WindShan on 2017/3/8. // Copyright © 2017年 WindShan. All rights reserved. // #ifndef ClientSocket_h #define ClientSocket_h #include #include #include #include #include #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::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::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::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 lst_send; list lst_rec; pthread_t t_id; pthread_t rec_tid; }; #endif /* ClientSocket_h */