1
require('socket.io').listen(3000)
这样就是监视3000端口了,由于我用的免费服务器,没有权限打开其他端口,所以,我还是使用80了,由于80已经被express使用了,所以我只好在express使用的时候传进来了。
var server = http.createServer(app)
var socket = require('./socket/msg')(server)
然后 我在msg.js里是这样写的
var db = require('../db/mysql')
var sio = require('socket.io')
var IO = function(server) {
var io = sio.listen(server)
这样就和谐了,db是创建mysql连接的方法,不在本节内容里,略。
在socket.io里是这样的,首先创建一个io通道的连接,然后监视里面的socket的事件,nodejs是事件驱动嘛。代码如下:
io.on('connection', function(socket) {
console.log('a user connected.')
socket.on('disconnect', function() {
console.log('user disconnected.')
})
})
这时只要有用户连接上,就会进入connection中了,然后它的参数是个socket,如果是公聊,我们可以直接用
1
io.emit('chat message', {})
这种形式了。但我们这里是私聊,所以我们要临时的把这个socket对象保存在全局里,供与你私聊的对象使用找到你的socket,很绕口,其实这里的私聊,不算完全的点对点,它还是经过了服务器的,消息传给服务器,服务器再找到你要传达给的那个人的socket对象,发给他。这就是整个的过程了。这里我使用的是一个类数组对象来存储的.
var users = {},
usocket = {}
socket.on('user join', function(data) {
users[username] = username
usocket[username] = socket
})
由于我这里需要用户名登录,所以我就把用户名作为了唯一的标识,这里用类数组的形式的好处就是我不用循环也能够很快的找到它。再我给A发送私聊时,我会先在这个uscoket里面找到它,然后调用它的emit。
function sendUserMsg(data) {
if (data.to in usocket) {
console.log('================')
console.log('to' + data.to, data)
usocket[data.to].emit('to' + data.to, data)
usocket[data.user].emit('to' + data.user, data)
console.log('================')
}
}
这里我emit了两次的原因是,我发给对方消息的同时,我自己也要收到这个消息,然后把它显示出来,为什么这样?其一,接口统一了,聊天里的内容全是服务器过来的,其二,证明我发送成功了。
然后我在客户端监听时,也用我自己的用户名起了一个to+用户名的事件监听。
socket.on('to' + user, function(data) {
//console.log(data)
formatMsg(data)
})
这样,不管是我发的消息,还是我收到消息,都会进入这个事件了。最后,在用户离开的时候别忘记delete掉这个对象。
socket.on('disconnect', function() {
console.log('disconnect')
if (username) {
counter--
delete users[username]
delete usocket[username]
if (home.name == username) {
homeLeave(username)
}
sendmsg({
type: 0,
msg: "用户<b>" + username + "</b>离开聊天室",
counter: counter,
users: users
})
}
})
连接流程代码如下:
var mysql = require('mysql') //调用MySQL模块//创建一个connectionvar connection = mysql.createConnection({
host : '127.0.0.1', //主机
user : 'root', //MySQL认证用户名
password:'12345',
port: '3306',
database: 'node'})//创建一个connectionconnection.connect(function(err){
if(err){
console.log('[query] - :'+err) return
}
console.log('[connection connect] succeed!')
})
//执行SQL语句connection.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
if (err) {
console.log('[query] - :'+err) return
}
console.log('The solution is: ', rows[0].solution)
})
//关闭connectionconnection.end(function(err){
if(err){
return
}
console.log('[connection end] succeed!')
})12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
关于Connection Optionos
要想创建一个数据库连接,先就要认识清楚Options
host:主机地址 (默认:localhost)
user:用户名
password:密码
port:端口号 (默认:3306)
database:数据库名
charset:连接字符集(默认:’UTF8_GENERAL_CI’,注意字符集的字母都要大写)
localAddress:此IP用于TCP连接(可选)
socketPath:连接到unix域路径,当使用 host 和 port 时会被忽略
timezone:时区(默认:’local’)
connectTimeout:连接超时(默认:不限制;单位:毫秒)
stringifyObjects:是否序列化对象(默认:’false’ ;与安全相关https://github.com/felixge/node-mysql/issues/501)
typeCast:是否将列值转化为本地JavaScript类型值 (默认:true)
queryFormat:自定义query语句格式化方法 https://github.com/felixge/node-mysql#custom-format
supportBigNumbers:数据库支持bigint或decimal类型列时,需要设此option为true (默认:false)
bigNumberStrings:supportBigNumbers和bigNumberStrings启用 强制bigint或decimal列以JavaScript字符串类型返回(默认:false)
dateStrings:强制timestamp,datetime,data类型以字符串类型返回,而不是JavaScript Date类型(默认:false)
debug:开启调试(默认:false)
multipleStatements:是否许一个query中有多个MySQL语句 (默认:false)
flags:用于修改连接标志,更多详情:https://github.com/felixge/node-mysql#connection-flags
ssl:使用ssl参数(与crypto.createCredenitals参数格式一至)或一个包含ssl配置文件名称的字符串,目前只捆绑Amazon RDS的配置文件
其它:
可以使用URL形式的加接字符串,不多介绍了,不太喜欢那种格式,觉得可读性差,也易出错,想了解的可以去主页上看。
MYSQL CURD *** 作
增加
var mysql = require('mysql')var DATABASE = "seckill"var TABLE="seckill"var connection = mysql.createConnection({
host:'127.0.0.1',
user:'root',
password:'12345',
port:'3306',
database: DATABASE
})
connection.connect()var addVip = 'insert into seckill(name,number) values(?,?)'var param = ['100元秒杀家教机',100]
connection.query(addVip, param, function(error, result){
if(error)
{
console.log(error.message)
}else{
console.log('insert id: '+result.insertId)
}
})
connection.end()12345678910111213141516171819202122232425
删除
var mysql = require('mysql')var DATABASE = "node"var TABLE="seckill"var connection = mysql.createConnection({
host:'127.0.0.1',
user:'root',
password:'12345',
port:'3306',
database: DATABASE
})
connection.connect()var addVip = 'delete from seckill where seckill_id = 1005'
connection.query(addVip, function(error, result){
if(error)
{
console.log(error.message)
}else{
console.log('affectedRows: '+result.affectedRows)
}
})
connection.end()123456789101112131415161718192021222324
查找
var mysql = require("mysql")var DATABASE = "node"var TABLE="seckill"var connection = mysql.createConnection({
host:'127.0.0.1',
user:'root',
password:'12345',
port:'3306',
})
connection.connect()
connection.query('use '+DATABASE)
connection.query('select * from '+TABLE, function(error, results, fields){
if (error) { throw error
} if (results) { for(var i = 0i <results.lengthi++)
{
console.log('%s\t%s',results[i].name,results[i].end_time)
}
}
})
connection.end()12345678910111213141516171819202122232425
修改
var mysql = require('mysql')var DATABASE = "seckill"var connection = mysql.createConnection({
host:'127.0.0.1',
user:'root',
password:'12345',
port:'3306',
database: DATABASE
})
connection.connect()var userSql = "update seckill set number = number-1 where seckill_id = ?"var param = [1000, 2]
connection.query(userSql, param, function (error, result) {
if(error)
{
console.log(error.message)
}else{
console.log('affectedRows: '+result.affectedRows)
}
})
connection.end()123456789101112131415161718192021
结束连接其实有两种方法end(),destory();
end()
end()方法在queries都结束后执行,end()方法接收一个回调函数,queries执行出错,仍然后结束连接,错误会返回给回调函数err参数,可以在回调函数中处理!
destory()
比较暴力,没有回调函数,即刻执行,不管queries是否完成!
使用连接池
在数据库中执行如下代码创建一个存储过程
DROP PROCEDURE IF EXISTS `P_SeckillInfo`DELIMITER CREATE DEFINER=`root`@`localhost` PROCEDURE `P_SeckillInfo`(IN ExtName VARCHAR(120),IN ExtNumber INT(11),OUT ExtReturnVal INT)TOP: BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN
ROLLBACK
SET ExtReturnVal = 0 -- Failed
END
START TRANSACTION
INSERT INTO seckill(name, number) VALUES(ExtName,ExtNumber)
SET ExtReturnVal = 1
SELECT ExtReturnVal
COMMITEND
DELIMITER 12345678910111213141516171819202122232425262728293031323334
调用示例:
var mysql = require("mysql")var pool = mysql.createPool({host: '127.0.0.1',
user: 'root',
password:'12345',
port:'3306',
database:'node'})//监听connection事件pool.on('connection', function(connection) {
connection.query('select * from seckill', function(error, results, fields){
if (error) { throw error
} if (results) { for(var i = 0i <results.lengthi++)
{
console.log('%s\t%s',results[i].name,results[i].end_time)
}
}
})
})//连接池可以直接使用,也可以共享一个连接或管理多个连接(引用官方示例)//直接使用pool.query('SELECT 1 + 1 AS solution', function(err, rows, fields) {
if (err) throw err
console.log('The solution is: ', rows[0].solution)
})//共享连接function myQuery(sql){
pool.getConnection(function(err, connection) {
connection.query(sql, function(err, result) {
console.log(result) //释放连接
connection.release()
}) //Error: Connection already released,应该每次到连接池中再次获取
// connection.query( 'SELECT * FROM seckill', function(err, result) {
// console.log(result)
// connection.release()
// })
})
}
myQuery('SELECT * FROM seckill')
myQuery('SELECT * FROM seckill')123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
1.连接池的创建,使用createPool方法,options和createConntion一致;
2.其它连接池配置选项
waitForConnections
当连接池没有连接或超出最大限制时,设置为true且会把连接放入队列,设置为false会返回error
connectionLimit
连接数限制,默认:10
queueLimit
最大连接请求队列限制,设置为0表示不限制,默认:0
断开重连
示例代码:
var mysql = require('mysql')var db_config = {host: '127.0.0.1',
user: 'root',
password:'12345',
port:'3306',
database:'node'}var connectionfunction handleDisconnect() {
connection = mysql.createConnection(db_config)
connection.connect(function(err) {
if(err) {
console.log('进行断线重连:' + new Date())
setTimeout(handleDisconnect, 2000) //2秒重连一次
return
}
console.log('连接成功')
})
connection.on('error', function(err) {
console.log('db error', err) if(err.code === 'PROTOCOL_CONNECTION_LOST') {
handleDisconnect()
} else {
throw err
}
})
}
handleDisconnect()12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
首先关闭mysql服务,然后执行程序,会一直打印断线重连,当再次开启mysql服务后,打印连接成功。
防止SQL注入
可以使用pool.escape()和connect.escape(),示例代码:
var mysql = require('mysql')var pool = mysql.createPool({host: '127.0.0.1',
user: 'root',
password:'12345',
port:'3306',
database:'node'})function myQuery(sql){
pool.getConnection(function(err,connection){
connection.query(sql,function(err,result){
//console.log(err)
console.log(result)
connection.release()
}) // connection.query('SELECT * FROM userinfo WHERE id = ' + pool.escape('5 OR ID = 6') ,function(err,result){
// //console.log(err)
// console.log(result)
// connection.release()
// })
})
}
myQuery('SELECT * FROM seckill WHERE seckill_id = ' + '1006 OR seckill_id = 1007')
myQuery('SELECT * FROM seckill WHERE seckill_id = ' + pool.escape('1006 OR seckill_id = 1007'))123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
结果可以看出,第1个query拼接条件可以被执行,而通过escape方法转义后的忽略了后面的拼接的部分!
遇到的问题
编码导致的问题
1366 (HY000): Incorrect string value: ‘\xC3\xEB\xC9\xB1’ for column ‘ExtName’ at row 1
字符编码没有统一的问题,查看数据库的编码方式命令为:
mysql>show variables like ‘character%’
从以上信息可知数据库的编码为latin1,需要修改为gbk或者是utf8;
nodejs中我们使用net模块来创建tcp服务器,tcp客户端,实现服务器与客户端之前的数据通信创建tcp服务器
var server=net.createServer([optations],[connectionListener])
optations:{allowHalfOpen:boolean}
allowHalfOpen:false 当服务器接受到客户端发送的一个FIN包时候,会回发一个FIN包,当为true时服务器不会回FIN包,使得tcp服务器可以继续发送数据到客户端,但是不会接受客户端发送的数据,开发者必须调动end方法来关闭socket,默认是false
connectionListener:当客户端与服务器连接上了,可以触发的回调函数。
function(socket){
//.......
}
我们也可以不用回调函数来写连接上做什么处理,连接上会触发connection事件
var server=net.createServer()返回创建的tcp服务器
我们可以server.on('connection',function(socket){
})
在创建完tcp服务器我们通知服务器要监听客户端连接
server.listen(port,[host],[backlog],[callback])
port:监听的端口,为0时候tcp服务器分配一个随机的端口
host:监听的ip和主机名,省略该参数,服务器监听任何ipv4地址的客户端连接
backlog:指定等待队列中最大的客户端连接最大数量 默认511
当指定端口、ip这个时候服务器开始监听这个ip这个端口的客户端了,这个时候触发listening事件,可以指定callback参数来处理触发listening具体要做什么
我们也可以
server.on('lisening',function(){
//.......
})
创建一个tcp服务器后可以用server.address()查看tcp服务器监听的信息
var address=server.address()
addres是一个对象
prot :监听的端口
address:监听的ip
family:ipv4还是ipv6
我们可以使用getConnections()查看与服务器连接的客户端的数量
server.getConnections(callback)
callback:function(err,count){
}
err:错误信息
count:为连接服务器的数量
我们也可以设置最大的连接数,超过这个数字,服务器不允许连接
server.maxConnections=2
服务器关闭
server.close([callback])
这个 方法让tcp服务器拒绝新的客户端连接,原有已经连上的客户端是不关闭的,当所有的连接服务器的客户端关闭时候,服务器默认自动关闭,触发服务器的close事件
下面我们写一个tcp服务器
var net=require("net")
opations={allowHalfOpne:false}
var server=net.createServer(opations)
server.on('connection',function(socket){
server.maxConnections=2
console.log("服务器最大连接数为%s",server.maxConnections)
server.getConnections(function(err,count){
console.log("已经有%s个客户端连接",count)
})
console.log("%s客户端与服务器建立连接",server.address().address)
})
server.on('error',function(err){
throw err
})
server.on('listening',function(){
console.log("服务器开始监听%j",server.address())
console.log("服务器开始监听")
})
server.listen(9966,'192.168.0.3')
setTimeout(function(){
server.close(function(){
console.log("tcp服务器关闭11111")
})
console.log("tcp服务器关闭")
},20000)
注意连接成功的时候触发的connection事件,执行的方法,参数是一个socket端口对象,这个就是服务器所监听的端口对象,所以我们socket.address().address返回给我们的是监听ip
socket端口对象
port:端口
address:ip
family:ipv4 ipv6
socket端口对象,可以读取客户端发送的流数据,每次接收到客户端发送的数据触发data事件。
接受客户端发送的消息(在连接成功的触发函数中 让server监听data事件做相应的处理)
server.on('connection',function(socket){
socket.on('data',function(data){
socket.setEncoding("utf-8")
console.log(data)
//console.log(data.toString())
})
})
bytesRead为socket端口对象监听客户端发送的数据字节数
console.log(socket.bytesRead)
当客户端关闭时候,触发socket端口对象的end事件
我们把客户端连接发送的数据保存到一个文件下
var net=require("net")
var fs=require("fs")
var server =net.createServer()
var op={
flags:"a",
encoding:"utf-8"
}
var file=fs.createWriteStream('./socket.txt',op)
server.on('connection',function(socket){
socket.on('data',function(data){
file.write(data)
})
})
server.on('listening',function(){
console.log("监听开始")
})
server.listen('1111','192.168.0.3')
以管道形式发送数据到文件
var net=require("net")
var fs=require("fs")
var server =net.createServer()
var op={
flags:"a",
encoding:"utf-8"
}
var file=fs.createWriteStream('./socket.txt',op)
server.on('connection',function(socket){
//socket.on('data',function(data){
// file.write(data)
//})
socket.pipe(file,{end:false})
socket.on("end",function(){
file.end("wanbi")
})
})
server.on('listening',function(){
console.log("监听开始")
})
server.listen('1111','192.168.0.3')
tcp客户端
创建tcp客户端
var client =new net.socket([opations])
optation:fd 一个现有的socket端口对象文件描述
type :ipv4 、ipv6
allowHalfOpne:true、false
连接服务器
client.connect(prot,[host],[callback])
host不指定默认为本地ip
回调函数表示连接上了做什么
若没有可以socket端口对象触发connect事件
client.on("connect",function(){
})
当我们连接成功后客户端服务器端的socket端口对象有下面的属性
remoteAddress、remotePort、localAddress、localPort
socket端口对象可以写入服务器、客户端流数据
socket.write(data,[encodeing],[callback])
写入数据少时候我们直接写入缓存区,数据很多时候,缓存区满了,我们要把数据写入缓存队列中,这个时候write(data) 返回false,触发drain
我们可以用bufferSize看缓存队列中有多少个字节
socket.on("error",function(err){
})
当遇到error时候这个socket端口对象应该销毁
socket.destory()
socket.end([data],[encoding])
这个方法表示我们要关闭socket端口对象,这个不是关闭服务器的close方法,后者是关闭服务器,实现的效果是不能让客户端连接了,前者是关闭连接(socket端口对象)
当我们使用服务器的socket端口对象(连接客户端得)的end(data,encoding)方法时候,会触发客户端socket端口对象end事件
服务器:
socket.end('88')
客户端会执行下面的代码:
client.on("end",function(){
//......
})
服务器端不会退出应用程序,即使所有的客户端都断开了,这个时候我们要server.unref(),退出程序,可以用server.ref()阻止程序退出.
当socket端口对象彻底关闭时候会触发close事件,我们可以指定当端口对象关闭时候做的处理
socket.on(''close',faction(had_error){
if(had_error){}
else{}
})
socket.writtenBytes表示写了多少个字节
我们tcp服务器与客户端连接了,但是突然间有一个断电了,来不及向另一端发送关闭连接的FIN包,这样另一边这个socket端口永远处于连接状态,我们用socket.setKeepAlive([enable],[inteval])定时向另一端发送监测包,
我们实现一个服务器读一个文件的信息,当有客户单连接上,吧这个信息传给客户端,输出在控制台
服务器代码
var net=require("net")
var fs=require("fs")
var server =net.createServer()
var op={
flags:"r",
encoding:"utf-8"
}
var file=fs.createReadStream('./socket.txt',op)
server.on('connection',function(socket){
file.on('data',function(data){
socket.write(data)
})
socket.on("end",function(){
file.end("wanbi")
})
})
server.on('listening',function(){
console.log("监听开始")
})
server.listen('1111','192.168.0.3')
客户端代码
var net=require("net")
var client=new net.Socket()
client.connect(1111,'192.168.0.3')
client.on('connect',function(){
console.log("ok")
})
client.on("data",function(data){
console.log(data.toString())
})
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)