nodejs 怎么把socket数据写入数据库

nodejs 怎么把socket数据写入数据库,第1张

先说下我对socket.io的理解,websocket更像是开启了一个端口服务,来监视过往的通讯。所以我们可以依赖于当前站点80端口启socket服务,也可以放于其他端口上,比如:

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())

})


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5900422.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-03-07
下一篇 2023-03-07

发表评论

登录后才能评论

评论列表(0条)

保存