CentOS7源码安装node.js和webSocket
学习参考:http://ourjs.com/detail/529ca5950cb6498814000005
如果iptables是开启的,要先加入80端口和socket监听端口(可以自己设置)
官网:https://nodejs.org
下载页面:https://nodejs.org/download/release/
中文手册:http://nodeapi.ucdok.com/#/api/
# yum -y installgcc gcc-c++ openssl-devel libssl-dev (如果是安装到32位系统需要再安装:yum install glibc.i686 zlib.i686)
我在编译安装node时出现下面错误,解决办法:
# yum whatprovides libstdc++.so.6 //找到对于依赖的包,然后安装
# cd/data/software && wget -c https://nodejs.org/download/release/latest-v9.x/node-v9.0.0-linux-x86.tar.gz&& tar -zxvf node-v9.0.0-linux-x86.tar.gz && cd node-v9.0.0-linux-x86/bin && ./node
出现上图说明nodejs安装成功了
# cp /data/software/node-v9.0.0-linux-x86/bin/* /usr/sbin/ && node -v
# cd/data/software/node-v9.0.0-linux-x86/lib/node_modules/npm &&./configure && make &&make install
修改npm的命令文件中的basedir路径,否则执行npm命令时老是报错
# cd /usr/lib/node_modules/npm/bin&& vi npm
basedir="/usr/lib"
# cp/usr/lib/node_modules/npm/bin/npm /usr/sbin/npm && npm -v
上图说明npm安装成功
使用npm命令安装express和socket.io 如果只是临时安装 Express,不想将它添加到依赖列表中,只需略去 --save 参数即可,安装 Node 模块时,如果指定了 --save 参数,那么此模块将被添加到 package.json 文件中 dependencies 依赖列表中。 然后通过 npm install 命令即可自动安装依赖列表中所列出的所有模块。
如果安装上面内容出错时,则给npm初始化,生成一个package.json文件:
# mkdir -p /data/software/node_modules && cd /data/software/node_modules&& npm init
下面红色标记的要手动输入:
最后生成下面红色标记文件:
# cd /usr/lib/node_modules&& npm install --save express && npm install --savesocket.io && ls
如上图红色标记,说明安装成功
建立网站根目录:
# mkdir /dataweb/www&& cd /dataweb/www && mkdir nodejs //作为nodejs存放服务器端的js目录,要和网页根目录分开,而且不能通过url地址访问的到
把express 和 socket.io 拷贝过来,因为server.js要引用:
# cp -r /data/software/node_modules/socket.io/ nodejs/
# cp -r /data/software/node_modules/express/ nodejs/
# cd nodejs
# viserver.js //作为webSocket服务器端
var app =require('./express')();
var http =require('http').Server(app);
var io = require('./socket.io')(http);
app.get('/',function(req, res){
res.send('
});
//在线用户
var onlineUsers ={};
//当前在线人数
var onlineCount =0;
io.on('connection',function(socket){
console.log('a user connected');
//监听新用户加入
socket.on('login', function(obj){
//将新加入用户的唯一标识当作socket的名称,后面退出的时候会用到
socket.name = obj.userid;
//检查在线列表,如果不在里面就加入
if(!onlineUsers.hasOwnProperty(obj.userid)) {
onlineUsers[obj.userid] = obj.username;
//在线人数+1
onlineCount++;
}
//向所有客户端广播用户加入
io.emit('login',{onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});
console.log(obj.username+'加入了聊天室');
});
//监听用户退出
socket.on('disconnect', function(){
//将退出的用户从在线列表中删除
if(onlineUsers.hasOwnProperty(socket.name)) {
//退出用户的信息
var obj = {userid:socket.name,username:onlineUsers[socket.name]};
//删除
delete onlineUsers[socket.name];
//在线人数-1
onlineCount--;
//向所有客户端广播用户退出
io.emit('logout',{onlineUsers:onlineUsers, onlineCount:onlineCount, user:obj});
console.log(obj.username+'退出了聊天室');
}
});
//监听用户发布聊天内容
socket.on('message', function(obj){
//向所有客户端广播发布的消息
io.emit('message', obj);
console.log(obj.username+'说:'+obj.content);
});
});
http.listen(3000,function(){
console.log('listening on *:3000');
});
# node index.js
建立客户端的js文件:
# vi client.js
(function () {
var d = document,
w = window,
p = parseInt,
dd = d.documentElement,
db = d.body,
dc = d.compatMode == 'CSS1Compat',
dx = dc ? dd: db,
ec = encodeURIComponent;
w.CHAT = {
msgObj:d.getElementById("message"),
screenheight:w.innerHeight ?w.innerHeight : dx.clientHeight,
username:null,
userid:null,
socket:null,
//让浏览器滚动条保持在最低部
scrollToBottom:function(){
w.scrollTo(0,this.msgObj.clientHeight);
},
//退出,本例只是一个简单的刷新
logout:function(){
//this.socket.disconnect();
location.reload();
},
//提交聊天消息内容
submit:function(){
var content =d.getElementById("content").value;
if(content != ''){
var obj = {
userid: this.userid,
username: this.username,
content: content
};
this.socket.emit('message',obj);
d.getElementById("content").value = '';
}
return false;
},
genUid:function(){
return new Date().getTime()+""+Math.floor(Math.random()*899+100);
},
//更新系统消息,本例中在用户加入、退出的时候调用
updateSysMsg:function(o, action){
//当前在线用户列表
var onlineUsers = o.onlineUsers;
//当前在线人数
var onlineCount = o.onlineCount;
//新加入用户的信息
var user = o.user;
//更新在线人数
var userhtml = '';
var separator = '';
for(key in onlineUsers) {
if(onlineUsers.hasOwnProperty(key)){
userhtml +=separator+onlineUsers[key];
separator = '、';
}
}
d.getElementById("onlinecount").innerHTML = '当前共有 '+onlineCount+' 人在线,在线列表:'+userhtml;
//添加系统消息
var html = '';
html += '
html += user.username;
html += (action == 'login') ? ' 加入了聊天室' : ' 退出了聊天室';
html += '
var section =d.createElement('section');
section.className = 'systemJ-mjrlinkWrap J-cutMsg';
section.innerHTML = html;
this.msgObj.appendChild(section);
this.scrollToBottom();
},
//第一个界面用户提交用户名
usernameSubmit:function(){
var username =d.getElementById("username").value;
if(username != ""){
d.getElementById("username").value = '';
d.getElementById("loginbox").style.display = 'none';
d.getElementById("chatbox").style.display= 'block';
this.init(username);
}
return false;
},
init:function(username){
/*
客户端根据时间和随机数生成uid,这样使得聊天室用户名称可以重复。
实际项目中,如果是需要用户登录,那么直接采用用户的uid来做标识就可以
*/
this.userid = this.genUid();
this.username = username;
d.getElementById("showusername").innerHTML = this.username;
this.msgObj.style.minHeight =(this.screenheight - db.clientHeight + this.msgObj.clientHeight) +"px";
this.scrollToBottom();
//连接websocket后端服务器(到时转为线上服务器)
this.socket = io.connect('ws://192.168.12.180:3000');
//告诉服务器端有用户登录
this.socket.emit('login',{userid:this.userid, username:this.username});
//监听新用户登录
this.socket.on('login',function(o){
CHAT.updateSysMsg(o, 'login');
});
//监听用户退出
this.socket.on('logout',function(o){
CHAT.updateSysMsg(o, 'logout');
});
//监听消息发送
this.socket.on('message',function(obj){
var isme = (obj.userid ==CHAT.userid) ? true : false;
var contentDiv ='
var usernameDiv =''+obj.username+'';
var section =d.createElement('section');
if(isme){
section.className = 'user';
section.innerHTML =contentDiv + usernameDiv;
} else {
section.className ='service';
section.innerHTML =usernameDiv + contentDiv;
}
CHAT.msgObj.appendChild(section);
CHAT.scrollToBottom();
});
}
};
//通过“回车”提交用户名
d.getElementById("username").onkeydown = function(e) {
e = e || event;
if (e.keyCode === 13) {
CHAT.usernameSubmit();
}
};
//通过“回车”提交信息
d.getElementById("content").onkeydown = function(e) {
e = e || event;
if (e.keyCode === 13) {
CHAT.submit();
}
};
})();
把下面的js代码拷贝到本地,用于兼容IE8以下浏览器能够解析json格式字符串
http://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js
去https://socket.io 找到最新版本的socket.io.js 然后拷贝到 /data/software/www/目录下面用于调用(或者去:/data/software/node_modules/socket.io/node_modules/socket.io-client/socket.io.js找)
# find / -name socket.io.js
# cp /data/software/node_modules/socket.io/node_modules/socket.io-client/socket.io.js /data/software/www/
# cd /data/software/www
建立用于客户端聊天的网页
# vi index.html
请先输入你在聊天室的昵称
把刚才几个js文件加载进去:
修改nginx配置文件(前提是已经安装了nginx):
# vi /usr/local/nginx/conf/nginx.conf
然后通过浏览器访问:http://192.168.12.180/
测试环境:访问前先关闭iptables
如下图,说明成功了:
如果firebug出现下面错误,很有可能是服务器端的nodejs(上面的node index.js)关闭了
把nodejs的模块都安装到下面目录
# cd /data/software/node-v0.12.9-linux-x64/bin/node_modules
安装mysql扩展:
# npm install --save mysql
安装redis扩展:(参考:http://my.oschina.net/robanlee/blog/261720)
# npm install --save redis
# vi index.js
//连接mysql数据库
var mysql = require('/data/software/node-v0.12.9-linux-x64/bin/node_modules/mysql');
var conn =mysql.createConnection({
host : '127.0.0.1',
user : 'test_user',
password : '888888',
port : 3306,
database : 'test'
});
conn.connect();
conn.query('select* from `cmge_account`', function(err, rows, fields) {
if (err) throw err;
console.log('The solution is: ', rows);
});
conn.end();
//调用redis模块
var redis =require("/data/software/node-v0.12.9-linux-x64/bin/node_modules/redis");
var client =redis.createClient(6379,'127.0.0.1',{connect_timeout:1}); //增加超时选项
//console.log(client);
client.info(function(err,response){
// console.log(err,response);
});
//get & set
client.set('roban','this is an testing val', function(err, response) {
if (err) {
console.log('Failed to set key ofroban, error:' + err);
return false;
}
client.get('roban',function(errGet,responseGet){
console.log('Val:'+responseGet);
});
});
在开发Node.js 实现的HTTP 应用时会发现,无论你修改了代码的哪一部份,都必须终止
Node.js 再重新运行才会奏效。这是因为Node.js 只有在第一次引用到某部份时才会去解析脚本文件,以后都会直接访问内存,避免重复载入,而PHP 则总是重新读取并解析脚本(如
果没有专门的优化配置)。Node.js的这种设计虽然有利于提高性能,却不利于开发调试,因
为我们在开发过程中总是希望修改后立即看到效果,而不是每次都要终止进程并重启。
supervisor 可以帮助你实现这个功能,它会监视你对代码的改动,并自动重启Node.js
# npm install -gsupervisor
# supervisor test_server.js &
让nodejs应用当成服务,在后台执行
# nohup nodeserver.js &
或者安装forever能做更多的事情,比如分别记录输出和错误日志,比如可以在js中作为api使用
# npm installforever -g #安装
$ forever startapp.js #启动
$ forever stopapp.js #关闭
$ forever start -lforever.log -o out.log -e err.log app.js #输出日志和错误
下面的-w参数是自动监控文件变化,文件修改保存了自动重启test_server.js
# forever -wtest_server.js
用脚本判断nodejs进程是否存在,如果不存在则自动启动
# vi node.sh
#!/bin/sh
#监测客服服务器端的进程是否存在,如果不存在则启动
while :
do
sleep 1
RESULT=`ps -e|grep'/usr/bin/supervisor test_server.js'|sed -e "/grep/d"`
if [ -z"$RESULT" ];then #判断RESULT是否为空,为空则说明进程未启动
/usr/bin/supervisor test_server.js
fi
done
#sh node.sh
# crontab -e
0 */2 * * * sh /data/cmge/oss2.cmge.com/nodejs/node.sh
如果要用域名访问nodejs做的web网站,需要在nginx的配置文件修改:
针对nodejs崩溃自动重启问题,可以参考:https://github.com/Unitech/pm2
# npm install pm2-g # 安装 PM2
# pm2 start test_server_new.js--watch # 启动和自动重启node
pm2 starttest_server_new.js --watch --log ‘/data/log/nodejs/kf2.shengli.com/’
pm2 monit
pm2 start server_new2.js --watch
Nodejs内存监测:
参考:http://web.jobbole.com/85684/
node--max-old-space-size=512 server_new2.js
说明:--max-old-space-size 限制占用内存大小,单位:M