642 lines
20 KiB
Markdown
642 lines
20 KiB
Markdown
# 面试专用贴
|
||
|
||
# 网络编程TCPdemo
|
||
|
||
tcpgetfiles tcppullfiles分别为上传和下载模块
|
||
|
||
demo中使用的框架类函数定义和实现,在EL文件夹中
|
||
|
||
|
||
## socket通讯类定义
|
||
|
||
```
|
||
// socket通讯的客户端类
|
||
class ctcpclient
|
||
{
|
||
private:
|
||
int m_connfd; // 客户端的socket.
|
||
string m_ip; // 服务端的ip地址。
|
||
int m_port; // 服务端通讯的端口。
|
||
public:
|
||
ctcpclient(): m_connfd(-1),m_port(0) { } // 构造函数。
|
||
|
||
// 向服务端发起连接请求。
|
||
// ip:服务端的ip地址。
|
||
// port:服务端通讯的端口。
|
||
// 返回值:true-成功;false-失败。
|
||
bool connect(const string &ip,const int port);
|
||
|
||
// 接收对端发送过来的数据。
|
||
// buffer:存放接收数据缓冲区。
|
||
// ibuflen: 打算接收数据的大小。
|
||
// itimeout:等待数据的超时时间(秒):-1-不等待;0-无限等待;>0-等待的秒数。
|
||
// 返回值:true-成功;false-失败,失败有两种情况:1)等待超时;2)socket连接已不可用。
|
||
bool read(string &buffer,const int itimeout=0); // 接收文本数据。
|
||
bool read(void *buffer,const int ibuflen,const int itimeout=0); // 接收二进制数据。
|
||
|
||
// 向对端发送数据。
|
||
// buffer:待发送数据缓冲区。
|
||
// ibuflen:待发送数据的大小。
|
||
// 返回值:true-成功;false-失败,如果失败,表示socket连接已不可用。
|
||
bool write(const string &buffer); // 发送文本数据。
|
||
bool write(const void *buffer,const int ibuflen); // 发送二进制数据。
|
||
|
||
// 断开与服务端的连接
|
||
void close();
|
||
|
||
~ctcpclient(); // 析构函数自动关闭socket,释放资源。
|
||
};
|
||
|
||
// socket通讯的服务端类
|
||
class ctcpserver
|
||
{
|
||
private:
|
||
int m_socklen; // 结构体struct sockaddr_in的大小。
|
||
struct sockaddr_in m_clientaddr; // 客户端的地址信息。
|
||
struct sockaddr_in m_servaddr; // 服务端的地址信息。
|
||
int m_listenfd; // 服务端用于监听的socket。
|
||
int m_connfd; // 客户端连接上来的socket。
|
||
public:
|
||
ctcpserver():m_listenfd(-1),m_connfd(-1) {} // 构造函数。
|
||
|
||
// 服务端初始化。
|
||
// port:指定服务端用于监听的端口。
|
||
// 返回值:true-成功;false-失败,一般情况下,只要port设置正确,没有被占用,初始化都会成功。
|
||
bool initserver(const unsigned int port,const int backlog=5);
|
||
|
||
// 从已连接队列中获取一个客户端连接,如果已连接队列为空,将阻塞等待。
|
||
// 返回值:true-成功的获取了一个客户端连接,false-失败,如果accept失败,可以重新accept。
|
||
bool accept();
|
||
|
||
// 获取客户端的ip地址。
|
||
// 返回值:客户端的ip地址,如"192.168.1.100"。
|
||
char *getip();
|
||
|
||
// 接收对端发送过来的数据。
|
||
// buffer:存放接收数据的缓冲区。
|
||
// ibuflen: 打算接收数据的大小。
|
||
// itimeout:等待数据的超时时间(秒):-1-不等待;0-无限等待;>0-等待的秒数。
|
||
// 返回值:true-成功;false-失败,失败有两种情况:1)等待超时;2)socket连接已不可用。
|
||
bool read(string &buffer,const int itimeout=0); // 接收文本数据。
|
||
bool read(void *buffer,const int ibuflen,const int itimeout=0); // 接收二进制数据。
|
||
|
||
// 向对端发送数据。
|
||
// buffer:待发送数据缓冲区。
|
||
// ibuflen:待发送数据的大小。
|
||
// 返回值:true-成功;false-失败,如果失败,表示socket连接已不可用。
|
||
bool write(const string &buffer); // 发送文本数据。
|
||
bool write(const void *buffer,const int ibuflen); // 发送二进制数据。
|
||
|
||
// 关闭监听的socket,即m_listenfd,常用于多进程服务程序的子进程代码中。
|
||
void closelisten();
|
||
|
||
// 关闭客户端的socket,即m_connfd,常用于多进程服务程序的父进程代码中。
|
||
void closeclient();
|
||
|
||
~ctcpserver(); // 析构函数自动关闭socket,释放资源。
|
||
};
|
||
```
|
||
|
||
## socket通讯类实现
|
||
|
||
```
|
||
bool ctcpclient::connect(const string &ip,const int port)
|
||
{
|
||
// 如果已连接到服务端,则断开,这种处理方法没有特别的原因,不要纠结。
|
||
if (m_connfd!=-1) { ::close(m_connfd); m_connfd=-1; }
|
||
|
||
// 忽略SIGPIPE信号,防止程序异常退出。
|
||
// 如果send到一个disconnected socket上,内核就会发出SIGPIPE信号。这个信号
|
||
// 的缺省处理方法是终止进程,大多数时候这都不是我们期望的。我们重新定义这
|
||
// 个信号的处理方法,大多数情况是直接屏蔽它。
|
||
signal(SIGPIPE,SIG_IGN);
|
||
|
||
m_ip=ip;
|
||
m_port=port;
|
||
|
||
struct hostent* h;
|
||
struct sockaddr_in servaddr;
|
||
|
||
if ( (m_connfd = socket(AF_INET,SOCK_STREAM,0) ) < 0) return false;
|
||
|
||
if ( !(h = gethostbyname(m_ip.c_str())) )
|
||
{
|
||
::close(m_connfd); m_connfd=-1; return false;
|
||
}
|
||
|
||
memset(&servaddr,0,sizeof(servaddr));
|
||
servaddr.sin_family = AF_INET;
|
||
servaddr.sin_port = htons(m_port); // 指定服务端的通讯端口
|
||
memcpy(&servaddr.sin_addr,h->h_addr,h->h_length);
|
||
|
||
if (::connect(m_connfd, (struct sockaddr *)&servaddr,sizeof(servaddr)) != 0)
|
||
{
|
||
::close(m_connfd); m_connfd=-1; return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
void ctcpclient::close()
|
||
{
|
||
if (m_connfd >= 0) ::close(m_connfd);
|
||
|
||
m_connfd=-1;
|
||
m_port=0;
|
||
}
|
||
|
||
ctcpclient::~ctcpclient()
|
||
{
|
||
close();
|
||
}
|
||
|
||
bool ctcpserver::initserver(const unsigned int port,const int backlog)
|
||
{
|
||
// 如果服务端的socket>0,关掉它,这种处理方法没有特别的原因,不要纠结。
|
||
if (m_listenfd > 0) { ::close(m_listenfd); m_listenfd=-1; }
|
||
|
||
if ( (m_listenfd = socket(AF_INET,SOCK_STREAM,0))<=0) return false;
|
||
|
||
// 忽略SIGPIPE信号,防止程序异常退出。
|
||
// 如果往已关闭的socket继续写数据,会产生SIGPIPE信号,它的缺省行为是终止程序,所以要忽略它。
|
||
signal(SIGPIPE,SIG_IGN);
|
||
|
||
// 打开SO_REUSEADDR选项,当服务端连接处于TIME_WAIT状态时可以再次启动服务器,
|
||
// 否则bind()可能会不成功,报:Address already in use。
|
||
int opt = 1;
|
||
setsockopt(m_listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
|
||
|
||
memset(&m_servaddr,0,sizeof(m_servaddr));
|
||
m_servaddr.sin_family = AF_INET;
|
||
m_servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // 任意ip地址。
|
||
m_servaddr.sin_port = htons(port);
|
||
if (bind(m_listenfd,(struct sockaddr *)&m_servaddr,sizeof(m_servaddr)) != 0 )
|
||
{
|
||
closelisten(); return false;
|
||
}
|
||
|
||
if (listen(m_listenfd,backlog) != 0 )
|
||
{
|
||
closelisten(); return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool ctcpserver::accept()
|
||
{
|
||
if (m_listenfd==-1) return false;
|
||
|
||
int m_socklen = sizeof(struct sockaddr_in);
|
||
if ((m_connfd=::accept(m_listenfd,(struct sockaddr *)&m_clientaddr,(socklen_t*)&m_socklen)) < 0)
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
char *ctcpserver::getip()
|
||
{
|
||
return(inet_ntoa(m_clientaddr.sin_addr));
|
||
}
|
||
|
||
bool ctcpserver::read(void *buffer,const int ibuflen,const int itimeout) // 接收二进制数据。
|
||
{
|
||
if (m_connfd==-1) return false;
|
||
|
||
return(tcpread(m_connfd,buffer,ibuflen,itimeout));
|
||
}
|
||
|
||
bool ctcpserver::read(string &buffer,const int itimeout) // 接收文本数据。
|
||
{
|
||
if (m_connfd==-1) return false;
|
||
|
||
return(tcpread(m_connfd,buffer,itimeout));
|
||
}
|
||
|
||
bool ctcpclient::read(void *buffer,const int ibuflen,const int itimeout) // 接收二进制数据。
|
||
{
|
||
if (m_connfd==-1) return false;
|
||
|
||
return(tcpread(m_connfd,buffer,ibuflen,itimeout));
|
||
}
|
||
|
||
bool ctcpclient::read(string &buffer,const int itimeout) // 接收文本数据。
|
||
{
|
||
if (m_connfd==-1) return false;
|
||
|
||
return(tcpread(m_connfd,buffer,itimeout));
|
||
}
|
||
|
||
bool ctcpserver::write(const void *buffer,const int ibuflen) // 发送二进制数据。
|
||
{
|
||
if (m_connfd==-1) return false;
|
||
|
||
return(tcpwrite(m_connfd,(char*)buffer,ibuflen));
|
||
}
|
||
|
||
bool ctcpserver::write(const string &buffer)
|
||
{
|
||
if (m_connfd==-1) return false;
|
||
|
||
return(tcpwrite(m_connfd,buffer));
|
||
}
|
||
|
||
bool ctcpclient::write(const void *buffer,const int ibuflen)
|
||
{
|
||
if (m_connfd==-1) return false;
|
||
|
||
return(tcpwrite(m_connfd,(char*)buffer,ibuflen));
|
||
}
|
||
|
||
bool ctcpclient::write(const string &buffer)
|
||
{
|
||
if (m_connfd==-1) return false;
|
||
|
||
return(tcpwrite(m_connfd,buffer));
|
||
}
|
||
|
||
void ctcpserver::closelisten()
|
||
{
|
||
if (m_listenfd >= 0)
|
||
{
|
||
::close(m_listenfd); m_listenfd=-1;
|
||
}
|
||
}
|
||
|
||
void ctcpserver::closeclient()
|
||
{
|
||
if (m_connfd >= 0)
|
||
{
|
||
::close(m_connfd); m_connfd=-1;
|
||
}
|
||
}
|
||
|
||
ctcpserver::~ctcpserver()
|
||
{
|
||
closelisten(); closeclient();
|
||
}
|
||
|
||
bool tcpread(const int sockfd,void *buffer,const int ibuflen,const int itimeout) // 接收二进制数据。
|
||
{
|
||
if (sockfd==-1) return false;
|
||
|
||
// 如果itimeout>0,表示需要等待itimeout秒,如果itimeout秒后还没有数据到达,返回false。
|
||
if (itimeout>0)
|
||
{
|
||
struct pollfd fds;
|
||
fds.fd=sockfd;
|
||
fds.events=POLLIN;
|
||
if ( poll(&fds,1,itimeout*1000) <= 0 ) return false;
|
||
}
|
||
|
||
// 如果itimeout==-1,表示不等待,立即判断socket的缓冲区中是否有数据,如果没有,返回false。
|
||
if (itimeout==-1)
|
||
{
|
||
struct pollfd fds;
|
||
fds.fd=sockfd;
|
||
fds.events=POLLIN;
|
||
if ( poll(&fds,1,0) <= 0 ) return false;
|
||
}
|
||
|
||
// 读取报文内容。
|
||
if (readn(sockfd,(char*)buffer,ibuflen) == false) return false;
|
||
|
||
return true;
|
||
}
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
## 日志类定义
|
||
|
||
```
|
||
// 日志文件
|
||
class clogfile
|
||
{
|
||
ofstream fout; // 日志文件对象。
|
||
string m_filename; // 日志文件名,建议采用绝对路径。
|
||
ios::openmode m_mode; // 日志文件的打开模式。
|
||
bool m_backup; // 是否自动切换日志。
|
||
int m_maxsize; // 当日志文件的大小超过本参数时,自动切换日志。
|
||
bool m_enbuffer; // 是否启用文件缓冲区。
|
||
spinlock_mutex m_splock; // 自旋锁,用于多线程程序中给写日志的操作加锁。
|
||
|
||
public:
|
||
// 构造函数,日志文件的大小缺省100M。
|
||
clogfile(int maxsize=100):m_maxsize(maxsize){}
|
||
|
||
// 打开日志文件。
|
||
// filename:日志文件名,建议采用绝对路径,如果文件名中的目录不存在,就先创建目录。
|
||
// openmode:日志文件的打开模式,缺省值是ios::app。
|
||
// bbackup:是否自动切换(备份),true-切换,false-不切换,在多进程的服务程序中,如果多个进程共用一个日志文件,bbackup必须为false。
|
||
// benbuffer:是否启用文件缓冲机制,true-启用,false-不启用,如果启用缓冲区,那么写进日志文件中的内容不会立即写入文件,缺省是不启用。
|
||
// 注意,在多进程的程序中,多个进程往同一日志文件写入大量的日志时,可能会出现小混乱,但是,多线程不会。
|
||
// 1)多个进程往同一日志文件写入大量的日志时,可能会出现小混乱,这个问题并不严重,可以容忍;
|
||
// 2)只有同时写大量日志时才会出现混乱,在实际开发中,这种情况不多见。
|
||
// 3)如果业务无法容忍,可以用信号量加锁。
|
||
bool open(const string &filename,const ios::openmode mode=ios::app,const bool bbackup=true,const bool benbuffer=false);
|
||
|
||
// 把日志内容以文本的方式格式化输出到日志文件,并且,在日志内容前面写入时间。
|
||
template< typename... Args >
|
||
bool write(const char* fmt, Args... args)
|
||
{
|
||
if (fout.is_open()==false) return false;
|
||
|
||
backup(); // 判断是否需要切换日志文件。
|
||
|
||
m_splock.lock(); // 加锁。
|
||
fout << ltime1() << " " << sformat(fmt,args...); // 把当前时间和日志内容写入日志文件。
|
||
m_splock.unlock(); // 解锁。
|
||
|
||
return fout.good();
|
||
}
|
||
|
||
// 重载<<运算符,把日志内容以文本的方式输出到日志文件,不会在日志内容前面写时间。
|
||
// 注意:内容换行用\n,不能用endl。
|
||
template<typename T>
|
||
clogfile& operator<<(const T &value)
|
||
{
|
||
m_splock.lock();
|
||
fout << value;
|
||
m_splock.unlock();
|
||
|
||
return *this;
|
||
}
|
||
|
||
private:
|
||
// 如果日志文件的大小超过m_maxsize的值,就把当前的日志文件名改为历史日志文件名,再创建新的当前日志文件。
|
||
// 备份后的文件会在日志文件名后加上日期时间,如/tmp/log/filetodb.log.20200101123025。
|
||
// 注意,在多进程的程序中,日志文件不可切换,多线的程序中,日志文件可以切换。
|
||
bool backup();
|
||
public:
|
||
void close() { fout.close(); }
|
||
|
||
~clogfile() { close(); };
|
||
};
|
||
```
|
||
|
||
|
||
|
||
## 日志类实现
|
||
|
||
```
|
||
bool clogfile::open(const string &filename,const ios::openmode mode,const bool bbackup,const bool benbuffer)
|
||
{
|
||
// 如果日志文件是打开的状态,先关闭它。
|
||
if (fout.is_open()) fout.close();
|
||
|
||
m_filename=filename; // 日志文件名。
|
||
m_mode=mode; // 打开模式。
|
||
m_backup=bbackup; // 是否自动备份。
|
||
m_enbuffer=benbuffer; // 是否启用文件缓冲区。
|
||
|
||
newdir(m_filename,true); // 如果日志文件的目录不存在,创建它。
|
||
|
||
fout.open(m_filename,m_mode); // 打开日志文件。
|
||
|
||
if (m_enbuffer==false) fout << unitbuf; // 是否启用文件缓冲区。
|
||
|
||
return fout.is_open();
|
||
}
|
||
|
||
bool clogfile::backup()
|
||
{
|
||
// 不备份
|
||
if (m_backup == false) return true;
|
||
|
||
if (fout.is_open() == false) return false;
|
||
|
||
// 如果当前日志文件的大小超过m_maxsize,备份日志。
|
||
if (fout.tellp() > m_maxsize*1024*1024)
|
||
{
|
||
m_splock.lock(); // 加锁。
|
||
|
||
fout.close(); // 关闭当前日志文件。
|
||
|
||
// 拼接备份日志文件名。
|
||
string bak_filename=m_filename+"."+ltime1("yyyymmddhh24miss");
|
||
|
||
rename(m_filename.c_str(),bak_filename.c_str()); // 把当前日志文件改名为备份日志文件。
|
||
|
||
fout.open(m_filename,m_mode); // 重新打开当前日志文件。
|
||
|
||
if (m_enbuffer==false) fout << unitbuf; // 判断是否启动文件缓冲区。
|
||
|
||
m_splock.unlock(); // 解锁。
|
||
|
||
return fout.is_open();
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool cifile::open(const string &filename,const ios::openmode mode)
|
||
{
|
||
// 如果文件是打开的状态,先关闭它。
|
||
if (fin.is_open()) fin.close();
|
||
|
||
m_filename=filename;
|
||
|
||
fin.open(m_filename,mode);
|
||
|
||
return fin.is_open();
|
||
}
|
||
```
|
||
|
||
|
||
|
||
## xml函数族定义
|
||
|
||
```
|
||
// 解析xml格式字符串的函数族。
|
||
// xml格式的字符串的内容如下:
|
||
// <filename>/tmp/_public.h</filename><mtime>2020-01-01 12:20:35</mtime><size>18348</size>
|
||
// <filename>/tmp/_public.cpp</filename><mtime>2020-01-01 10:10:15</mtime><size>50945</size>
|
||
// xmlbuffer:待解析的xml格式字符串。
|
||
// fieldname:字段的标签名。
|
||
// value:传入变量的地址,用于存放字段内容,支持bool、int、insigned int、long、unsigned long、double和char[]。
|
||
// 注意:当value参数的数据类型为char []时,必须保证value数组的内存足够,否则可能发生内存溢出的问题,也可以用ilen参数限定获取字段内容的长度,ilen的缺省值为0,表示不限长度。
|
||
// 返回值:true-成功;如果fieldname参数指定的标签名不存在,返回失败。
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,string &value,const int ilen=0);
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,char *value,const int ilen=0);
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,bool &value);
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,int &value);
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,unsigned int &value);
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,long &value);
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,unsigned long &value);
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,double &value);
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,float &value);
|
||
```
|
||
|
||
|
||
|
||
## xml函数族实现
|
||
|
||
```
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,string &value,const int ilen)
|
||
{
|
||
string start="<"+fieldname+">"; // 数据项开始的标签。
|
||
string end="</"+fieldname+">"; // 数据项结束的标签。
|
||
|
||
int startp=xmlbuffer.find(start); // 在xml中查找数据项开始的标签的位置。
|
||
if (startp==string::npos) return false;
|
||
|
||
int endp=xmlbuffer.find(end); // 在xml中查找数据项结束的标签的位置。
|
||
if (endp==string::npos) return false;
|
||
|
||
// 从xml中截取数据项的内容。
|
||
int itmplen=endp-startp-start.length();
|
||
if ( (ilen>0) && (ilen<itmplen) ) itmplen=ilen;
|
||
value=xmlbuffer.substr(startp+start.length(),itmplen);
|
||
|
||
return true;
|
||
}
|
||
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,char *value,const int len)
|
||
{
|
||
if (value==nullptr) return false;
|
||
|
||
if (len>0) memset(value,0,len+1); // 调用者必须保证value的空间足够,否则这里会内存溢出。
|
||
|
||
string str;
|
||
getxmlbuffer(xmlbuffer,fieldname,str);
|
||
|
||
if ( (str.length()<=(unsigned int)len) || (len==0) )
|
||
{
|
||
str.copy(value,str.length());
|
||
value[str.length()]=0; // string的copy函数不会给C风格字符串的结尾加0。
|
||
}
|
||
else
|
||
{
|
||
str.copy(value,len);
|
||
value[len]=0;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,bool &value)
|
||
{
|
||
string str;
|
||
if (getxmlbuffer(xmlbuffer,fieldname,str)==false) return false;
|
||
|
||
toupper(str); // 转换为大写来判断(也可以转换为小写,效果相同)。
|
||
|
||
if (str=="TRUE") value=true;
|
||
else value=false;
|
||
|
||
return true;
|
||
}
|
||
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,int &value)
|
||
{
|
||
string str;
|
||
|
||
if (getxmlbuffer(xmlbuffer,fieldname,str)==false) return false;
|
||
|
||
try
|
||
{
|
||
value = stoi(picknumber(str,true)); // stoi有异常,需要处理异常。
|
||
}
|
||
catch(const std::exception& e)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,unsigned int &value)
|
||
{
|
||
string str;
|
||
|
||
if (getxmlbuffer(xmlbuffer,fieldname,str)==false) return false;
|
||
|
||
try
|
||
{
|
||
value = stoi(picknumber(str)); // stoi有异常,需要处理异常。不提取符号 + -
|
||
}
|
||
catch(const std::exception& e)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,long &value)
|
||
{
|
||
string str;
|
||
|
||
if (getxmlbuffer(xmlbuffer,fieldname,str)==false) return false;
|
||
|
||
try
|
||
{
|
||
value = stol(picknumber(str,true)); // stol有异常,需要处理异常。
|
||
}
|
||
catch(const std::exception& e)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,unsigned long &value)
|
||
{
|
||
string str;
|
||
|
||
if (getxmlbuffer(xmlbuffer,fieldname,str)==false) return false;
|
||
|
||
try
|
||
{
|
||
value = stoul(picknumber(str)); // stoul有异常,需要处理异常。不提取符号 + -
|
||
}
|
||
catch(const std::exception& e)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,double &value)
|
||
{
|
||
string str;
|
||
|
||
if (getxmlbuffer(xmlbuffer,fieldname,str)==false) return false;
|
||
|
||
try
|
||
{
|
||
value = stod(picknumber(str,true,true)); // stod有异常,需要处理异常。提取符号和小数点。
|
||
}
|
||
catch(const std::exception& e)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool getxmlbuffer(const string &xmlbuffer,const string &fieldname,float &value)
|
||
{
|
||
string str;
|
||
|
||
if (getxmlbuffer(xmlbuffer,fieldname,str)==false) return false;
|
||
|
||
try
|
||
{
|
||
value = stof(picknumber(str,true,true)); // stof有异常,需要处理异常。提取符号和小数点。
|
||
}
|
||
catch(const std::exception& e)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
```
|
||
|