📄 csocket.h
字号:
/*******************************************************************
* cSocket.h
* DESCRIPTION:
*
* AUTHOR:yyc---yycmail@263.sina.com
* http://yycnet.yeah.net
*
* HISTORY:
*
* DATE:2002-8-19
*
*******************************************************************/
#ifndef __CSOCKET_H__
#define __CSOCKET_H__
#include "osdef.h"
#include "cThread.h"
#include "cBuffer.h"
#include "cFifo.h"
#include <deque>
#include <map>
namespace yyc
{
#define EFULL_SOCK -1
#define ENULL_SOCK -2
#define EHANDLE_SOCK -3 //非法的socket 句柄
#define EMEM_SOCK -4 //创建对象失败/内存分配错误
#define ELIMIT_SOCK -5 //不能创建cSocket客户对象,超过Server的最大连接客户端限制数
#define ETHREAD_SOCK -6 //启动发送或接收线程出错或线程未启动
#define EARGS_SOCK -7 //传递参数错误
#define ECONN_SOCK -8 //连接指定的主机失败或此Csocket对象未连接
#define ESOCKET_SOCK -9 //创建socket失败
#define ESETOPT_SOCK -10 //调用setsockopt发生错误
#define EBIND_SOCK -11
#define ELISTEN_SOCK -12
#define OK_SOCK 0
//socket 接收线程回调函数--数据处理函数
//第一个参数为接收数据缓冲指针,第二个参数为接收数据的长度
//第三个参数为接收此数据的cSocket对象指针
//返回值为int型
//第1位指示是否关闭SOCKET连接,第2位指示关闭SOCKET连接是否等待缓冲区数据发送完成
class cSocket;
typedef int(FUNC_DODATA)(char *,int ,cSocket *);
class cSocket
{
private:
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
//保存cSocket服务对象的连接客户端的多线程安全集合
class clients
{
private:
//int为一个整型数,标识csocket对象
std::map<cSocket *,int> m_set;
//自增长的唯一标识csocket对象的整数
int m_hSocket;
cMutex m_mutex;
static const int MAX_CLIENT_NUM;//=50;
public:
clients();
int del(cSocket *psock);
int remove(cSocket *psock);
int add(cSocket *psock);
void clear();
cSocket *get(int index);
~clients();
int len()
{
return m_set.size();
}
};
//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
clients m_client_set;
int m_fd;//socket handle,default -1
char m_strHostip[20];//remote host ip
int m_iHostport;//remote host port
char m_strLocalip[20];//local host ip
int m_iLocalport;//local host port
int m_iStatus; //cSocket object status,SOCK_CLOSED:SOCK_CONNECTED:SOCK_LISTEN
int m_iType; //cSocket IP type 0-tcp 1-udp
int m_iComm; //cSocket communication type 0-none 1-recv 2-send 3-dual
bool m_bAutoclose;//auto close cSocket object if output buffer is empty
cThread m_recvThread;
cThread m_sendThread;
cFifo<cBuffer> m_in_buf; //接受缓冲区
cFifo<cBuffer> m_out_buf; //发送缓冲区
cSocket * m_pParent; //server cSocket object's point of creating this cSocket object
FUNC_DODATA * m_pfDodata; //function point of deal with received data
//记录外部对象对此cSocket对象的引用
//如果socket连接发生异常或中断,当外部引用计数为<=0时,则自动删除释放cSocket对象
int m_iRef;//cSocket object引用计数,default=1
void * m_pArgs;//point of other data that cSocket object request
public:
enum
{
SOCK_CLOSED,
SOCK_CONNECTED,
SOCK_LISTEN //侦听服务或客户服务状态
};
private:
//接收线程
static int recv_thread(void *args);
//发送线程
static int send_thread(void *args);
//启动收发线程
int start_thread();
/**
* 检查socket是否有数据到达f=0
* 检查socket是否可写 f=1
*
* @param wait_usec 最大超时等待时间(us)
*
* @return =0:没有数据
* >0:有数据可读,或socket可写
* <0:socket发生错误
*/
int checkdata(long wait_usec,int f=0);
/**
* 用指定的socket连接句柄初始化或创建cSocket客户对象
*
* @param fd 指定的socket连接句柄
* @param remoteip socket连接的主机IP
* @param remoteport socket连接的主机侦听端口
*
* @return <0:发生错误
* >=0:连接成功
* 如果此csocket对象为服务csocket,则自动创建一个普通csocket客户
* 连接指定的主机,并将此csocket对象保存到csocket服务对象的客户端缓冲区中,返回
* 新创建的csocket对象的句柄(从1开始)
* 如果为普通csocket客户对象,则返回0
*/
int createClient(int fd,const char *remoteip,int remoteport);
/**
* 从输入/输出缓冲区中的取数据
*
* @param buf 接收缓冲区数据地址空间
* @param size 接收缓冲区的最大长度
* @inORout 0--输入缓冲区 1--输出缓冲区
* @return 返回接收的数据大小
*/
int getdata(char *buf,int size,int inORout);
public:
cSocket();
~cSocket();
/**
* 发送数据到输出缓冲区
*
* @param fmt 格式化字符串
*
* @return 发送数据个数,<0发生错误
*/
int send(const char * fmt,...);
/**
* 发送数据到输出缓冲区
*
* @param len 发送数据大小
* @param buf 发送数据指针
*
* @return 发送数据个数,<0发生错误
*/
int send(int len,const char * buf);
/**
* 发送数据到输出缓冲区
* 当函数成功时,将更改*ppBuf=NULL,防止调用者释放*ppBuf空间
*
* @param len 发送数据大小
* @param buf 发送数据指针的指针
*
* @return 发送数据个数,<0发生错误
*/
int send(int len,char ** ppBuf);
/**
* 发送数据到输出缓冲区
* 当函数成功时,将更改*ppBuf=NULL,防止调用者释放*ppBuf空间
*
* @param len 发送数据大小
* @param buf 发送数据指针的指针
*
* @return 发送数据个数,<0发生错误
*/
int send(cBuffer **ppBuf);
/**
* 接收输入缓冲区中的数据
*
* @param buf 接收缓冲区数据地址空间
* @param size 接收缓冲区的最大长度
*
* @return 返回接收的数据大小
*/
int recv(char *buf,int size);
/**
* 接收输入缓冲区中的数据
* 此函数将分配内存接收输入缓冲区的数据,并将分配的内存指针写入ppBuf变量中返回
*
* @param ppBuf 保存接收缓冲区指针的地址指针
*
* @return 返回接收的数据大小
*/
int recv(char **ppBuf);
/**
* 接收输入缓冲区中的数据
*
* @param pbuf 接收数据的buffer对象
*
* @return <0,发生错误
* 返回接收的数据大小
*/
int recv(cBuffer *pbuf);
/**
* 往接收缓冲区中插入数据
*
* @param buf 插入数据的指针
* @param len 插入数据大小
*
* @return 插入数据大小
* <0 发生错误
*/
int fill(const char * buf,int len);
/**
* 将*ppBuf指向的对象压入接收缓冲区堆栈
* 当函数成功时,将更改*ppBuf=NULL,防止调用者释放*ppBuf空间
*
* @param ppBuf 要压入接收缓冲区的cBuffer对象指针的指针
*
* @return <0,发生错误
* 插入数据大小
*/
int fill(cBuffer **ppBuf);
/**
* 连接指定的主机
*
* @param remoteip 主机IP
* @param remoteport 主机侦听端口
*
* @return <0:发生错误
* >=0:连接成功
* 返回cSocket对象的句柄,客通过get_pSocket()函数返回cSocket对象的指针
*/
int connect(const char * remoteip,int remoteport);
int close();
/**
* 创建侦听服务cSocket对象
*
* @param iPort 侦听服务端口
* >=0启动服务并在指定的端口进行侦听
* 如果=0,则系统自动分配侦听服务端口,否则用用户指定的端口
* <0,启动服务,但不进行侦听
*
* @return <0:发生错误
* 否则返回侦听端口
*/
int listen(int iPort=0);
int status()
{
return m_iStatus;
}
/**
* 返回指定句柄的cSocket对象指针,并增加引用计数
*
* @param hSocket
*
* @return
*/
cSocket *get_pSocket(int hSocket)
{
cSocket *psock=NULL;
if(hSocket<0)
{
m_iRef--;
psock=this;
}
else if(hSocket==0)
{
m_iRef++;
psock=this;
}
else
{
//this object is Server object
psock=m_client_set.get(hSocket);
if(psock!=NULL)
psock->m_iRef++;
}
return psock;
}
int get_localhost_info(char **strLocalip=NULL)
{
if(strLocalip!=NULL) *strLocalip=m_strLocalip;
return m_iLocalport;
}
int get_remotehost_info(char **strRemoteip=NULL)
{
if(strRemoteip!=NULL) *strRemoteip=m_strHostip;
return m_iHostport;
}
void set_pfDodata(FUNC_DODATA *pf)
{
m_pfDodata=pf;
}
void set_pArgs(void *pArgs)
{
m_pArgs=pArgs;
}
void *get_pArgs()
{
return m_pArgs;
}
void set_bAutoclose(bool b)
{
m_bAutoclose=b;
}
bool get_bAutoclose()
{
return m_bAutoclose;
}
//查看输出/输入缓冲是否为空
//f=0,输出缓冲 =1输入缓冲
bool isEmpty(int f=0)
{
bool bRet;
if(f==0)
bRet=m_out_buf.empty();
else
bRet=m_in_buf.empty();
return bRet;
}
/**
* 清空缓冲区
*
* @param f 指明要清空的缓冲区
* -1----all
* 0----不清空
* 1----接收缓冲区
* 2----发送缓冲区
* 4----客户端对象缓冲区
*/
void clear(int f=0)
{
if((f & 1)!=0) m_in_buf.clear();
if((f & 2)!=0) m_out_buf.clear();
if((f & 4)!=0) m_client_set.clear();
}
};
//redefine my_usleep() replace usleep()
//有的操作系统没有usleep()函数
//同时usleep()在SUN unix下有可能导致永久阻塞
//因此将对系统的usleep函数的调用改为自建的函数调用
inline void my_usleep(unsigned int us)
{
struct timeval to;
to.tv_sec = 0;
//引该加保护,us必须>=0且小于1000000
//为了提高效率,此保护由调用者提供
to.tv_usec = us;
select(0, NULL, NULL, NULL, &to);
}
}//namespace yyc
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -