自己做为屌丝批评下自己,前两往篇文章我写得太烂了,连我自己都不想看,所以接下来的文章,如果写我就要写得让大家明白,不然不写
在上面两篇文章连篇标题改为 :用C++在Linux下开发聊天系统ChatServer
我所介绍的ChatServer采用的是Mongodb数据库
Mongodb是NoSQL类的数据库,目前也是NoSQL数据库最流行的,它的安装很简单,下载、解压即可
下载地址:http://www.mongodb.org/downloads
根据服务器的系统下载相应即可
解压后的文件 很简单,只一个bin目录和几个文件
启动:解压目录/bin/mongod --port 27017 --dbpath 数据存放目录 --auth
这里注意下--auth选项,这个代表是客户端要验证才能操作数据库,刚安装的时候不要该 --auth(还没有建立用户)
默认端口是27017,所以--port也是可以去掉的
第一步:/bin/mongod --dbpath ./data &
第二步:/bin/mongo
( 这里可以输入了)
1、要先建立一个管理数据库admin(必须是这个)
use admin
使用use 表示选择或新建一个数据库
2、设置用户密码
db.addUser('user,'pass')
成功后会出现ok之类的提示符
3、验证是否正确
db.auth('user','pass')
返回 1代表成功,0失败
4、然后我们按照上面的步骤建立ch1_config、ch1_data、ch1_log数据库,并要设置验证
5、退出
exit
====================以上建立完了===============================
下面我们来关掉Mongod数据库,再以验证(--auth)的方式启动
先找到mongodb进程
ps -ef|grep mongod
然后kill -9 进程ID 或killall mongod
然后去删除/data/下的mongodb.lock文件(这个很重要,很多人启动不成功都是因为它)
再次启动
/bin/mongod --auth --dbpath ./data &
===============================================================
这样不报错就代表成功了;好了,下面我来介绍下安装c++ mongodb driver
下载地址:http://dl.mongodb.org/dl/cxx-driver/
选择mongodb-linux-x86_64-v2.0-latest.tgz下载即可
下载后,在任意目录下解压,这个记录要安装pcre,scons(安装mongodb辅助工具)
下载pcre http://sourceforge.net/projects/pcre/files/pcre/8.00/
http://sourceforge.net/projects/scons/files/scons/2.1.0/
#rpm -ivh scons-2.1.0-1.noarch.rpm 安装完成
安装mongodb driver
解压#tar zxvf mongodb-linux-x86_64-v2.0-latest.tgz
#cd mongodb-linux-x86_64-v2.0
安装mongodb-driver是采用scons该软件辅助安装 的
# scons --extrapath=/usr/local/(自己的安装目录即可)
安装完成后会出现如下字符
scons: Reading SConscript files ...
Checking for C library boost_thread-mt... yes
Checking for C library boost_filesystem-mt... yes
Checking for C library boost_system-mt... yes
Checking for C library boost_thread-mt... yes
scons: done reading SConscript files.
scons: Building targets ...
File "/usr/bin/scons", line 178, in <module>
g++ -o client/examples/authTest.o -c -O3 -D_SCONS -DMONGO_EXPOSE_MACROS -Imongo client/examples/authTest.cpp
g++ -o mongo/buildinfo.o -c -O3 -D_SCONS -DMONGO_EXPOSE_MACROS -Imongo mongo/buildinfo.cpp
g++ -o mongo/pch.o -c -O3 -D_SCONS -DMONGO_EXPOSE_MACROS -Imongo mongo/pch.cpp
g++ -o mongo/bson/oid.o -c -O3 -D_SCONS -DMONGO_EXPOSE_MACROS -Imongo mongo/bson/oid.cpp
...省略一部分....
g++ -o authTest -Wl,--as-needed -Wl,-zdefs client/examples/authTest.o -L. -lmongoclient -lpthread -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt -lboost_thread-mt
.....省略一部分....
mongo/util/net/httpclient.os mongo/util/net/listen.os mongo/util/net/message.os mongo/util/net/message_port.os mongo/util/net/sock.os mongo/util/md5.os -lpthread -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt -lboost_thread-mt
g++ -o secondExample -Wl,--as-needed -Wl,-zdefs client/examples/second.o-L. -lmongoclient -lpthread -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt -lboost_thread-mt
g++ -o whereExample -Wl,--as-needed -Wl,-zdefs client/examples/whereExample.o -L. -lmongoclient -lpthread -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt -lboost_thread-mt
scons: done building targets.
这些信息很用,比如: -L. -lmongoclient -lpthread -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt -lboost_thread-mt
这个是在编译或链接时的参数,如果我们不注意这些信息,到我们去写代码手动或自动编译时就会出现各种神马的错误了,所以先记下来先,
好了,在当前目录下有几个测试文件,如firstExample、authTest,clentTest等,这个可以运行看看,它们是已经编译好的,运行没有什么问题,这里有还个client目录,里面有很多例子,我们可以打开eclispe,将这些例子放进去编译运行一下,这时是eclispe自动编译时,会出现奇怪的报错,下面看下最近我写的一人C++ Mongodb类:
注意下,我用了空间名
Mongodb.h
/*
* Mongodb.h
*
* Created on: 2012-10-26
* Author: root
*/
#ifndef MONGODB_H_
#define MONGODB_H_
#include "mongo/client/dbclient.h"
#include "../base/Exception.h"
#include "../config/ServerConfig.h"
#include "../util/StringFormat.h"
namespace consts {
using namespace std;
using namespace mongo;
using namespace config;
using namespace util;
using namespace base;
class Mongodb {
public:
Mongodb();
virtual ~Mongodb();
static DBClientConnection conn;
static void Init();
};
} /* namespace consts */
#endif /* MONGODB_H_ */
在这里时,首先要告诉大家,要将解压的src/include/mongo文件夹复制到/usr/local/include下,作为引入文件,当然放到系统有include的其他地方也行,如:/usr/include
Mongodb.cpp
/*
* Mongodb.cpp
*
* Created on: 2012-10-26
* Author: root
*/
#include "Mongodb.h"
namespace consts {
DBClientConnection Mongodb::conn;
Mongodb::Mongodb() {
// TODO Auto-generated constructor stub
}
Mongodb::~Mongodb() {
// TODO Auto-generated destructor stub
}
void Mongodb::Init() {
string errmsg;
// 连接
if (!conn.connect(
ServerConfig::GetDatabaseIp() + ":"
+ StringFormat::Int2Str(ServerConfig::GetDatabasePort()),
errmsg)) {
throw Exception(errmsg);
}
// 验证
if (!conn.auth(ServerConfig::GetDatabaseConfig(),
ServerConfig::GetDatabaseUser(), ServerConfig::GetDatabasePass(),
errmsg)) {
throw Exception(errmsg);
}
if (!conn.auth(ServerConfig::GetDatabaseData(),
ServerConfig::GetDatabaseUser(), ServerConfig::GetDatabasePass(),
errmsg)) {
throw Exception(errmsg);
}
if (!conn.auth(ServerConfig::GetDatabaseLog(),
ServerConfig::GetDatabaseUser(), ServerConfig::GetDatabasePass(),
errmsg)) {
throw Exception(errmsg);
}
}
} /* namespace consts */
这里有个抛错类,可以用输入字符串,再return 来代替
这里有个用到ServerConfig类,还在StringFormat,下面我也将这两个类粘代码上来:
StringFormat.h
/*
* StringFormat.h
*
* Created on: 2012-10-22
* Author: root
*/
#ifndef STRINGFORMAT_H_
#define STRINGFORMAT_H_
#include <iostream>
#include <string>
#include <vector>
#include <string.h>
#include <sstream>
#include <stdlib.h>
namespace util {
class StringFormat {
public:
StringFormat();
virtual ~StringFormat();
static int Str2Int(const std::string s);
static std::string Int2Str(const int i);
static std::vector<std::string> split(std::string str,std::string pattern);
};
} /* namespace util */
#endif /* STRINGFORMAT_H_ */
StringFormat.cpp
/*
* StringFormat.cpp
*
* Created on: 2012-10-22
* Author: root
*/
#include "StringFormat.h"
namespace util {
StringFormat::StringFormat() {
// TODO Auto-generated constructor stub
}
StringFormat::~StringFormat() {
// TODO Auto-generated destructor stub
}
int StringFormat::Str2Int(const std::string s){
return atoi(s.c_str());
}
std::string StringFormat::Int2Str(int i){
std::ostringstream oss;
oss << i;
return oss.str();
}
std::vector<std::string> StringFormat::split(std::string str,
std::string pattern) {
std::string::size_type pos;
std::vector<std::string> result;
str += pattern;
int size = str.size();
for (int i = 0; i < size; i++) {
pos = str.find(pattern, i);
if (pos < size) {
std::string s = str.substr(i, pos - i);
result.push_back(s);
i = pos + pattern.size() - 1;
}
}
return result;
}
} /* namespace util */
ServerConfig.h
/*
* ServerConfig.h
*
* Created on: 2012-10-25
* Author: root
*/
#ifndef SERVERCONFIG_H_
#define SERVERCONFIG_H_
#include <map>
#include <string>
#include "../util/StringFormat.h"
using namespace std;
using namespace util;
namespace config {
class ServerConfig {
public:
ServerConfig();
virtual ~ServerConfig();
static void Init(const std::string filename);
static string GetServerIp();
static int GetServerPort();
static string GetDatabaseIp();
static int GetDatabasePort();
static string GetDatabaseUser();
static string GetDatabasePass();
static string GetDatabaseConfig();
static string GetDatabaseData();
static string GetDatabaseLog();
private :
static map<string,string> _map;
};
} /* namespace config */
#endif /* SERVERCONFIG_H_ */
ServerConfig.cpp
/*
* ServerConfig.cpp
*
* Created on: 2012-10-25
* Author: root
*/
#include "ServerConfig.h"
#include "../util/Config.h"
namespace config {
map<string,string> ServerConfig::_map;
ServerConfig::ServerConfig() {
// TODO Auto-generated constructor stub
}
ServerConfig::~ServerConfig() {
// TODO Auto-generated destructor stub
}
void ServerConfig::Init(const std::string filename) {
Config::ReadConfig(filename, _map);
}
string ServerConfig::GetServerIp() {
return _map["ServerIp"];
}
int ServerConfig::GetServerPort(){
return StringFormat::Str2Int(_map["ServerPort"]);
}
string ServerConfig::GetDatabaseIp(){
return _map["DatabaseIp"];
}
int ServerConfig::GetDatabasePort(){
return StringFormat::Str2Int(_map["DatabasePort"]);
}
string ServerConfig::GetDatabaseUser(){
return _map["Database_User"];
}
string ServerConfig::GetDatabasePass(){
return _map["Database_Pass"];
}
string ServerConfig::GetDatabaseConfig(){
return _map["Database_config"];
}
string ServerConfig::GetDatabaseData(){
return _map["Database_config"];
}
string ServerConfig::GetDatabaseLog(){
return _map["Database_config"];
}
} /* namespace config */
这时还有个Config类,这个类主要加载配置文件用,很好用,从其他地方抄的,哈哈,下面作者不是我的名字啊
Config.h
/*
* Config.h
*
* Created on: 2012-10-24
* Author: root
*/
/****************************************************************************
* 作者: jasitzhang(张涛)
* 日期: 2011-10-2
* 目的: 读取配置文件的信息,以map的形式存入
* 要求: 配置文件的格式,以#作为行注释,配置的形式是key = value,中间可有空格,也可没有空格
*****************************************************************************/
#ifndef CONFIG_H_
#define CONFIG_H_
#define COMMENT_CHAR '#'
#include <string>
#include <map>
using namespace std;
namespace util {
class Config {
public:
Config();
virtual ~Config();
static bool ReadConfig(const string& filename,map<string,string>& m);
static void PrintConfig(const map<string,string>& m);
static bool IsSpace(char c);
static bool IsCommentChar(char c);
static void Trim(string& str);
static bool AnalyseLine(const string& line,string& key,string& value);
};
} /* namespace util */
#endif /* CONFIG_H_ */
Config.cpp
/*
* Config.cpp
*
* Created on: 2012-10-24
* Author: root
*/
#include <fstream>
#include <iostream>
#include "Config.h"
using namespace std;
namespace util {
Config::Config() {
// TODO Auto-generated constructor stub
}
Config::~Config() {
// TODO Auto-generated destructor stub
}
bool Config::IsSpace(char c) {
if (' ' == c || '\t' == c)
return true;
return false;
}
bool IsCommentChar(char c) {
switch (c) {
case COMMENT_CHAR:
return true;
default:
return false;
}
}
void Config::Trim(string& str){
if(str.empty()){
return ;
}
int i, start_pos,end_pos;
for(i=0;i<str.size();++i){
if(!IsSpace(str[i])){
break;
}
}
if( i == str.size() ){ // 全部是空白字符串
str = "" ;
return ;
}
start_pos = i ;
for(i = str.size() - 1 ; i >= 0; --i) {
if(!IsSpace(str[i])){
break;
}
}
end_pos = i;
str = str.substr(start_pos , end_pos - start_pos + 1);
}
bool Config::AnalyseLine(const string& line,string & key,string & value){
if(line.empty()){
return false;
}
int start_pos = 0, end_pos = line.size() - 1,pos;
if((pos = line.find(COMMENT_CHAR))!=-1){
if(0 == pos){// 行的第一个字符就是注释字符
return false;
}
end_pos = pos -1;
}
string new_line = line.substr(start_pos,start_pos + 1 - end_pos);// // 预处理,删除注释部分
if((pos = new_line.find('=')) == -1){
return false; // 没有=号
}
key = new_line.substr(0,pos);
value = new_line.substr(pos + 1 ,end_pos + 1 - (pos + 1 )) ;
Trim(key);
if(key.empty()){
return false;
}
Trim(value);
return true;
}
bool Config::ReadConfig(const string& filename,map<string,string> & m){
m.clear();
ifstream infile(filename.c_str());
if(!infile){
cout << "file open error " << endl;
}
string line,key,value;
while(getline(infile,line)){
if(AnalyseLine(line,key,value)){
m[key] = value;
}
}
infile.close();
return true;
}
void Config::PrintConfig(const map<string,string>& m){
map<string,string>::const_iterator mite = m.begin();
for(; mite != m.end(); ++ mite){
cout << mite ->first << "=" << mite->second << endl;
}
}
} /* namespace util */
还有个server.cfg
##=============服务器==================
## 服务器IP ##
ServerIp = 192.168.154.131
## 服务器端口 ##
ServerPort = 8800
##=============数据库=================
## 数据库IP ##
DatabaseIp = 192.168.154.131
## 数据库端口 ##
DatabasePort = 27017
##
Database_User = root
Database_Pass= root
## 数据库data ##
Database_config = ch1_data
Database_data = ch1_data
Database_log = ch1_log
几乎所有文件 都贴上去了,那就开始编译吧,但老是报错,这是因为少了某些库,又如自己又加了-lboost_thread等,还是错,这里我们刚才说到要保存编译mongodb driver的编译信息的用处了,哈哈,
好,如果是用eclispe的就要项目的编译选项( c/c++ build -> setting-> *-flag )中追加如下信息
-L. -lmongoclient -lpthread -lboost_thread-mt -lboost_filesystem-mt -lboost_system-mt -lboost_thread-mt
手动编译就要后面直接加上去就行了
到此肯定可以成功的了
谢谢各位的阅读,本人博客年龄尚轻,希望得到各位的指正,谢谢!
=============================================================