广州设计公司网站,网站源码下载后怎么用,网站的主域名,莆田软件定制开发node.js的事件循环
node.js是基于事件驱动的#xff0c;通常在代码中注册想要等待的事件#xff0c;设定好回调函数#xff0c;当事件触发的时候就会调用回调函数。如果node.js没有要处理的事件了#xff0c;那整个就结束了;事件里面可以继续插入事件#xff0c;如果有事…node.js的事件循环
node.js是基于事件驱动的通常在代码中注册想要等待的事件设定好回调函数当事件触发的时候就会调用回调函数。如果node.js没有要处理的事件了那整个就结束了;事件里面可以继续插入事件如果有事件是一直要继续下去的那么node 也就不会退出了,每一次事件处理结束后等待下一个事件的发生
console.log(HelloWorld);// 计时器事件, 每隔一段事件触发一次, time的单位是毫秒
/*setInterval(function () {console.log(get time doing);
}, 5 * 1000); // 每间隔5秒调用一次*/// 插入一个事件让它多长时间以后执行一次
setTimeout(function() {console.log(set time out);
}, 3 * 1000);// process是node的一个全局模块
console.log(process.pid);
console.log(process.version);
console.log(process.platform);
console.log(process.title);
console.log(process.argv); // 在启动的时候我们可以往程序里面传入参数,参数都是字符串var argc process.argv.length;
if (argc 3) {console.log(process.argv[2]);
}console.log(process.execPath); // node所在的路径
console.log(process.env); // 获得系统的环境变量// 当我们的node在每次退出的时候都会抛出一个exit这样一个事件如果我们用户监听这个事件那么
// 当有exit事件发生的时候我们之前设置的回掉函数将会倍调用
// process.on来监听事件
process.on(exit, function() {console.log(now node exit!!!!);
});// 当我们发生了一个未知的异常的时候我们调用这个回掉函数;
// node 停止处理当前这个事件继续等待下一个事件的处理不会整个退出
// 服务器就不会随意的奔溃
// 可以把这个错误保存起来方便我们去查找
process.on(uncaughtException, function(err) {console.log(uncaughtException called , err);
});
// 当我们的程序如果运行的时候有异常那么这个时候我们可以通过捕获异常
// 如果说我们没有捕获的异常这个uncaughtException
// 如果发生uncaughtExceptionnode是会退出的;
// 没有主动捕获所以javascript解释器他是不会继续执行的;
// current work director 当前的工作目录
// ./ --- C:\Home\workspace\node_js
// process.chdir(C:\\Home\\workspace); // 修改我们的工作目录工作目录默认你的node是在哪个目录下启动的就是那个目录为你的工作目录
console.log(process.cwd());// while处理时间进入等待时间之前调用完成后去事件里面来等待新的事件发生
process.nextTick(function() {console.log(nextTick);
});TCP网络连接和数据交换
node.js一般用on来监听对应的事件
服务器
// 将net模块 引入进来
var net require(net);// 创建一个net.Server用来监听,当连接进来的时候就会调用我们的函数
// client_sock,就是我们的与客户端通讯建立连接配对的socket
// client_sock 就是与客户端通讯的net.Socket
var server net.createServer(function(client_sock) { console.log(client comming, client_sock.remoteAddress, client_sock.remotePort);// 设置你接受的格式, // client_sock.setEncoding(utf8);// client_sock.setEncoding(hex); // 转成二进制的文本编码// // 客户端断开连接的时候处理,用户断线离开了client_sock.on(close, function() {console.log(close socket);});// 接收到客户端的数据调用这个函数// data 默认是Buffer对象如果你强制设置为utf8,那么底层会先转换成utf8的字符串传给你// hex 底层会把这个Buffer对象转成二进制字符串传给你// 如果你没有设置任何编码 Buffer 48 65 6c 6c 6f 57 6f 72 6c 64 21// utf8 -- HelloWorld!!! hex-- 48656c6c6f576f726c6421client_sock.on(data, function(data) {console.log(data);client_sock.write(goodbye!!!);client_sock.end(); // 正常关闭});client_sock.on(error, function(err) {console.log(error, err);});
});// 当我开始监听的时候就会调用这个回掉函数
server.on(listening, function() {console.log(start listening...);
});// 监听发生错误的时候调用
server.on(error, function() {console.log(listen error);
});server.on(close, function() {console.log(server stop listener);
});
/*
server.on(connection, function(client_sock) {console.log(client comming 22222);
});
*/
// 编写代码指示这个server监听到哪个端口上面。
// 127.0.0.1: 6080
// node就会来监听我们的server,等待连接接入
server.listen({port: 6080,host: 127.0.0.1,exclusive: true,
});// 停止node对server的监听事件处理那么node就没有其他的事件要处理所以就退出了。
// server.unref(); // 取消node,对server的事件的监听
// server.close(); // 主动的掉这个server.close才会触发这个net.Server的close事件客户端
var net require(net);// net.Socket,
var sock net.connect({port: 6080,host: 127.0.0.1,
}, function() {console.log(connected to server!);
});// 连接成功调用的事件
sock.on(connect,function() {console.log(connect success);// 在这里我们就可以发送数据了sock.write(HelloWorld!, utf8);// end
});
// end// 有错误发生调用的事件
sock.on(error, function(e) {console.log(error, e);
});// socket关闭的事件
sock.on(close, function() {console.log(close);
});// 对方发送了关闭数据包过来的事件
sock.on(end, function() {console.log(end event);
});// 当有数据发生的时候调用;
sock.on(data, function(data) {console.log(data);
});内存管理Buffer模块与大小端
1:4个字节的数据存到内存的4个字节; 小尾: LE高位的数据 -- 高地址字节地方 -- “高高低低” 大尾: BE高位的数据 -- 低地址字节地方; 2: 通常我们的计算机的CPU小尾存储;
分配 Buffer.alloc(); Buffer.allocUnsafe(); Buffer.allocUnsafeSlow Buffer.from(array); Buffer.from(buf); Buffer.from(string); 获取Buffer的长度 buf.length;
读写 1: Buffer读取字节 buf[index]; 2:根据数据属于大尾小尾来决定使用BE/LE; 3: readFloatBE/readDoubleBE / readFloatLE/readDoubleLE; 4: 读/写整数: read/write Int8/UInt Int16BE/Int16LE/UInt16BE/UInt16LE Int32BE/Int32LE/UInt32BE/UInt32LE IntBE/IntLE/UIntBE/UIntLE floatBE/floatLE/doublBE/doubleLE
常用方法 1:Buffer.byteLength(str, encoding) 返回字符对象对应的二进制长度; 2: 交换swap16, swap32, swap64 大尾小尾数据变化; 3: bu.values(); 遍历buf里面的每个字节; 4: buf转字符串 buf.toString(); 5: Buffer转json字符串 JSON.stringify(buf) buf.toJSON; 6: buf.fill用特定的数据填充buffer
// (1)给定一个大小
// (2)会给这些内存一个初值如果你没有指定那么这个初值就是0
var buf Buffer.alloc(10, 0xff);
console.log(buf);// (1) 给定分配一个给定大小的Buffer的内存
// (2) 不会对这些内存区赋初值的,随机的数据它原来是什么就是什么
// Unsafe 指的是没有初始化的内存
buf Buffer.allocUnsafe(10);
console.log(buf);// 不重Buffer缓冲区里面分配直接从操作系统分配
// Slow指的是没有重缓冲池里面高效的分配
// Unsafe, 指的是内存没有被初始化
buf Buffer.allocUnsafeSlow(10);
console.log(buf);// 获得我们的bufer对象的长度
// Buffer一旦分配大小再也不能改变。
console.log(buf.length);// 方便的创建方式复制
// 创建一个Buffer对象用来存放这个字符串的二进制
buf Buffer.from(Helloworld!);
console.log(buf);buf Buffer.from([123, 22, 24, 36, 47, -1]);
console.log(buf);// 重新创建一个Buffer,然后把原来Buffer的数据拷贝给新的Buffer
var buf2 Buffer.from(buf);
console.log(buf2);// buf[index] index [0, len - 1];
console.log(buf[0], buf[1]);// 以大尾的形式存放 4个字节的整数
// 0x00 00 ff ff ---655535
// 00 00 ff ff
// start从哪里开始
buf.writeInt32BE(65535, 0);
console.log(buf);// ff ff 00 00
buf.writeInt32LE(65535, 0);
console.log(buf);// offset是从哪里开始的位置
var value buf.readInt32LE(0);
console.log(value);buf.writeFloatLE(3.14, 0);
console.log(buf.readFloatLE(0));var len Buffer.byteLength(HelloWorld);
console.log(len);len Buffer.byteLength(buf2);
console.log(len);// 4个字节的Int为例 4 * 4 16;
// 0, 1, 2, 3,| 4, 5, 6, 7, |8, 9, 10, 11, |12, 13, 14, 15
buf Buffer.alloc(4 * 4);
buf.writeInt32LE(65535, 0);
buf.writeInt32LE(65535, 4);
buf.writeInt32LE(65535, 8);
buf.writeInt32LE(65535, 12);
console.log(buf);
buf.swap32();
// 3, 2, 1, 0,| 7, 6, 5, 4, |11, 10, 9, 8, |15, 14, 13, 12
console.log(buf);console.log(buf.readInt32BE(0));
console.log(buf.readInt32BE(4));
console.log(buf.readInt32BE(8));
console.log(buf.readInt32BE(12));for(var v of buf.values()) {console.log(v);
}// 二进制 根据特定的编码来转字符串
console.log(buf.toString(utf8));
// 0000ffff0000ffff0000ffff0000ffff
console.log(buf.toString(hex));console.log(buf.toJSON());buf.fill(A);
console.log(buf);
console.log(buf.toString(utf8));buf.fill(hello);
console.log(buf);
console.log(buf.toString(utf8));
npm的安装和管理
1:node.js生态里的第三方模块可以通过npm工具来安装和使用,方便大家开发; 2: npm 安装 node.js 模块: npm install 模块名称 本地安装)运行目录/node_modules npm install -g 模块名称 (全局安装 安装到系统的node_modules下)
注意安装之前使用npm init命令初始化一个package.json文件这是当前项目的依赖模块
1:require项目文件 .js代码.json文本, .node二进制必须要使用:绝对路径(/), 相对路径(./, …/)开头 2: 没有写后缀名和路径的require项目文件默认为第三方库,依次加载: .js, .json. node; 3: 如果没有以绝对路径开头或以相对路径开头的为加载模块: (1)系统模块去查找是否能找到; (2)当前项目文件夹搜索 ./node_modules; (3) 上一级项目文件夹搜索 ./node_modules,直到全部搜索完成;
websocket的使用
1:websocket 是一种通讯协议底层是TCP socket, 基于TCP,它加入了自己的协议用来传输数据; 2: websocket是h5为了上层方便的使用socket而实现的; 3: 发送数据带着长度信息能避免粘包的问题; 4: 客户端/服务器像事件驱动一样的编写代码不用考虑底层复杂的事件模型;
服务器
// 加载node上websocket模块 ws;
var ws require(ws);// 启动基于websocket的服务器,监听我们的客户端接入进来。
var server new ws.Server({host: 127.0.0.1,port: 6080,
});// 监听接入进来的客户端事件
function websocket_add_listener(client_sock) {// close事件client_sock.on(close, function() {console.log(client close);});// error事件client_sock.on(error, function(err) {console.log(client error, err);});// end // message 事件, data已经是根据websocket协议解码开来的原始数据// websocket底层有数据包的封包协议所以绝对不会出现粘包的情况。// 每解一个数据包就会触发一个message事件;// 不会出现粘包的情况send一次就会把send的数据独立封包。// 想我们如果是直接基于TCP我们要自己实现类是于websocket封包协议client_sock.on(message, function(data) {console.log(data);client_sock.send(Thank you!);});// end
}// connection 事件, 有客户端接入进来;
function on_server_client_comming (client_sock) {console.log(client comming);websocket_add_listener(client_sock);
}server.on(connection, on_server_client_comming);// error事件,表示的我们监听错误;
function on_server_listen_error(err) {}
server.on(error, on_server_listen_error);// headers事件, 回给客户端的字符。
function on_server_headers(data) {// console.log(data);
}
server.on(headers, on_server_headers);
客户端
var ws require(ws);
// url ws://127.0.0.1:6080
// 创建了一个客户端的socket,然后让这个客户端去连接服务器的socket
var sock new ws(ws://127.0.0.1:6080);
sock.on(open, function () {console.log(connect success !!!!);sock.send(HelloWorld1);sock.send(HelloWorld2);sock.send(HelloWorld3);sock.send(HelloWorld4);sock.send(Buffer.alloc(10));
});sock.on(error, function(err) {console.log(error: , err);
});sock.on(close, function() {console.log(close);
});sock.on(message, function(data) {console.log(data);
});使用浏览器时
!DOCTYPE html
html
headtitleskynet WebSocket example/title
/head
body scriptvar ws new WebSocket(ws://127.0.0.1:6080/ws);ws.onopen function(){alert(open);ws.send(WebSocket); };ws.onmessage function(ev){alert(ev.data);};ws.onclose function(ev){alert(close);};ws.onerror function(ev){console.log(ev);alert(error);};/script
/body
/htmlTCP的拆包封包
1: 在通讯的过程中,我们可能有发送多个数据包数据包A数据包B,数据包C,此时我们最好的期望是每次收到数据包A数据包B,数据包C。但是TCP底层为了传送性能可能会一次把ABC所有数据一起传过来这个时候收到的是ABC这个时候上层傻眼了无法区分A,B,C这个叫做—粘包;
处理方式 1:要解决ABC数据包无法正确的拆分出A,B,C三个数据,我们需要在ABC之间插入长度/分解标志,这样根据长度和分解标志来解析出ABC的数据包; 2: 打入长度信息两种方式:(1)“数据长度” 包体 (2)(包体 特定的结尾符号) 3: 本例采用 数据长度 包体的方式。数据长度个字节超过个字节大小的数据上层可以分多次发送; 4: 这里的包是上层的应用协议的包与TCP的包是两回事;
工具脚本netpkg.js
var netpkg {// 根据封包协议我们读取包体的长度;read_pkg_size: function(pkg_data, offset) {if (offset pkg_data.length - 2) { // 没有办法获取长度信息的;return -1; }var len pkg_data.readUInt16LE(offset);return len;},// 把一个要发送的数据,封包 2个字节的长度 数据// data string 二进制的bufferpackage_data: function(data) {var buf Buffer.allocUnsafe(2 data.length);buf.writeInt16LE(2 data.length, 0);buf.fill(data, 2);return buf;},unpack_cmd_from_data: function(client_sock, data) {var last_pkg client_sock.last_pkg;var cmd_set [];if (last_pkg ! null) { // 上一次剩余没有处理完的半包;var buf Buffer.concat([last_pkg, data], last_pkg.length data.length);last_pkg buf;}else {last_pkg data; }var offset 0;var pkg_len netpkg.read_pkg_size(last_pkg, offset);if (pkg_len 0) {return cmd_set;}while(offset pkg_len last_pkg.length) { // 判断是否有完整的包;// 根据长度信息来读取我们的数据,架设我们穿过来的是文本数据var cmd_buf Buffer.allocUnsafe(pkg_len - 2); // 2个长度信息last_pkg.copy(cmd_buf, 0, offset 2, offset pkg_len);cmd_set.push(cmd_buf);offset pkg_len;if (offset last_pkg.length) { // 正好我们的包处理完了;break;}pkg_len netpkg.read_pkg_size(last_pkg, offset);if (pkg_len 0) {break;}}// 能处理的数据包已经处理完成了,保存 0.几个包的数据if (offset last_pkg.length) {last_pkg null;}else { // offset, length这段数据拷贝到新的Buffer里面var buf Buffer.allocUnsafe(last_pkg.length - offset);last_pkg.copy(buf, 0, offset, last_pkg.length);last_pkg buf;}// end client_sock.last_pkg last_pkg;return cmd_set;}, // 模拟底层TCP 粘包的问题test_pkg_two_action: function(action1, action2) {var buf Buffer.allocUnsafe(2 2 action1.length action2.length);buf.writeInt16LE(2 action1.length, 0);buf.fill(action1, 2);var offset 2 action1.length;buf.writeInt16LE(2 action2.length, offset);buf.fill(action2, offset 2);return buf},// 模拟的一个大的数据包分两次发送到客户端;// one cmd half_cmd half_cmd2test_pkg_two_slice: function(half_cmd1, half_cmd2) {// var buf1 Buffer.allocUnsafe(2 half_cmd1.length);buf1.writeInt16LE(2 half_cmd1.length half_cmd2.length, 0);buf1.fill(half_cmd1, 2);var buf2 Buffer.allocUnsafe(half_cmd2.length);buf2.fill(half_cmd2, 0);return [buf1, buf2];}
};module.exports netpkg;服务器脚本tcpserver.js
var net require(net);
var netpkg require(./netpkg);
var protocol require(./protocol);function process_one_cmd(sock, cmd) {console.log(cmd);var data protocol.decode(cmd);console.log(data);
}var server net.createServer(function(client_sock) { console.log(client comming, client_sock.remoteAddress, client_sock.remotePort);client_sock.last_pkg null;client_sock.on(close, function() {console.log(close socket);});client_sock.on(data, function(data) {var cmd_set netpkg.unpack_cmd_from_data(client_sock, data);for(var key in cmd_set) {process_one_cmd(client_sock, cmd_set[key]);}});client_sock.on(error, function(err) {console.log(error, err);});
});server.on(listening, function() {console.log(start listening...);
});server.on(error, function() {console.log(listen error);
});server.on(close, function() {console.log(server stop listener);
});server.listen({port: 6080,host: 127.0.0.1,exclusive: true,
});二进制数据协议、Json数据协议
二进制协议优点是数据包小传输效率高缺点是要在代码中单独定义每个协议的封包解包这个过程可以利用protobuf来进行。 Json协议优点是可以用同一种方式进行封包解包可读性强。缺点是包体较大需要使用数字作为key来减小包体。 这里我们规定了传输的数据包含三个部分0服务号1命令号2数据下面的代码体现了这两种协议的封包和解包。
var bin_encode {0: {// 账号登陆的二进制协议打包, stype 0, cmd_type 1,// data.uname 存放数据名字, data.upwd 密码 {uname: xxxx, upwd xxxx };// 制定了我们的登陆命令协议前个字节存放服务号后两个字节我们存放命令号后面我们存放uname字符串的长度占2个字节;// 紧接着uname字符串的内容接着是upwd的长度信息占两个字节紧接着是upwd的内容;1: function (data) { // encode_login_cmd // 前面2个字节来存放我们的服务号var cmd_len 2 2 2 data[0].length 2 data[1].length;var cmd_buf Buffer.allocUnsafe(cmd_len);// 写入两个字节的服务号cmd_buf.writeUInt16LE(0, 0); // 写入了0号服务cmd_buf.writeUInt16LE(1, 2); // 紧跟两个字节我们写这个命令的命令号// end // 数据体// unamevar len data[0].length;cmd_buf.writeUInt16LE(len, 4); // 写入了0号服务cmd_buf.fill(data[0], 4 2);// upwdlen data[1].length;var offset 6 data[0].length;cmd_buf.writeUInt16LE(len, offset); // 写入了0号服务cmd_buf.fill(data[1], offset 2);// end return cmd_buf;},},};var bin_decode {0: {// return 1: function(cmd_buf) {var cmd {0: 0,1: 1,2: null,};var len cmd_buf.readUInt16LE(4); // uname的长度var offset 4 2;var data {};data.uname cmd_buf.toString(utf8, offset, len offset);offset len;len cmd_buf.readUInt16LE(offset); // uname的长度offset 2;data.upwd cmd_buf.toString(utf8, offset, len offset); cmd[2] data; return cmd;},}
}function bin_encode_cmd(stype, cmd_type, data) {if (bin_encode[stype] bin_encode[stype][cmd_type]) {return bin_encode[stype][cmd_type](data);}return null;
}function bin_decode_cmd(cmd_buf) {// 前面2个字节是服务号接着两个字节是命令号var stype cmd_buf.readUInt16LE(0);var cmd_type cmd_buf.readUInt16LE(2);if (bin_decode[stype] bin_decode[stype][cmd_type]) {return bin_decode[stype][cmd_type](cmd_buf);}return null;// end
}var bin_protocol {encode: bin_encode_cmd,decode: bin_decode_cmd,
}function json_encode(stype, cmd_type, data) {var data {0: stype,1: cmd_type,2: data,};var cmd_buf JSON.stringify(data);console.log(cmd_buf);return cmd_buf;
}function json_decode(cmd_buf) {var cmd_data JSON.parse(cmd_buf);console.log(cmd_data);return cmd_data;
}var json_protocol {encode: json_encode,decode: json_decode,
}
module.exports bin_protocol;
// module.exports json_protocol;Http基础和Webserver
1: http server是一种支持http协议的服务器; 2: http server监听在一个端口上面等待客户端的http连接; 3: 客户端创建一个TCP socket 连接到服务器; 4: 客户端像服务器发送一个 http协议的请求数据包; 5: 服务器获得这个请求然后返回一个http响应数据包; 6: 服务器关闭Tcp socket, 客户端也关闭TCP socket; 7:Connection:keep-alive 如果有再次访问这个服务器上的网页会继续使用这一条已经建立的连接Keep-Alive不会永久保持连接它有一个保持时间默认是马上关闭;
请求方法: GET, POST, HEAD, PUT, DELETE, OPTIONS,TRACE, CONNECT使用GET和POST即可满足一般需求 Post相比于Get不同的地方在于可以携带Body数据数据内容通过Content-type体现
var express require(express);
var path require(path);
// 工作目录/www_root静态网页存放的根目录index.html是入口文件
var app express();
app.use(express.static(path.join(process.cwd(), www_root)));
app.listen(6080);// web url的响应函数http://127.0.0.1:6080/login访问动态网页
app.get(/login, function (request, respones) {console.log(request.query);// 底层会打包成http协议的回应发送给客户端respones.send(SUCCESS!);
});
客户端Get和Post的数据传输
var http require(http);
/*[100] Continue,[101] Switching Protocols,[200] OK,[201] Created,[202] Accepted,[203] Non-Authoritative Information,[204] No Content,[205] Reset Content,[206] Partial Content,[300] Multiple Choices,[301] Moved Permanently,[302] Found,[303] See Other,[304] Not Modified,[305] Use Proxy,[307] Temporary Redirect,[400] Bad Request,[401] Unauthorized,[402] Payment Required,[403] Forbidden,[404] Not Found,[405] Method Not Allowed,[406] Not Acceptable,[407] Proxy Authentication Required,[408] Request Time-out,[409] Conflict,[410] Gone,[411] Length Required,[412] Precondition Failed,[413] Request Entity Too Large,[414] Request-URI Too Large,[415] Unsupported Media Type,[416] Requested range not satisfiable,[417] Expectation Failed,[500] Internal Server Error,[501] Not Implemented,[502] Bad Gateway,[503] Service Unavailable,[504] Gateway Time-out,[505] HTTP Version not supported,
}
*/
/*
callback(is_success, data/erro)
*/
// get请求的参数是带在URL的地址上面的
function http_get(ip, port, url, params, callback) {// step1,创建一个 http.ClientRequestvar options {host: 127.0.0.1,port: port,path: url ? params,method: GET};// 当有请求返回的时候参数就会被传递为http.IncomingMessagevar req http.request(options, function(incoming_msg) {console.log(respones status incoming_msg.statusCode);// 监听IncomingMessage的data事件当收到服务器发过来的数据的时候触发这个事件incoming_msg.on(data, function(data) {if (incoming_msg.statusCode 200) {callback(true, data);}});});// 把这个请求发送出去req.end();
}/*
http_get(127.0.0.1, 6080, /login, unameblakeupwd123456, function(is_ok, data) {if (is_ok) {console.log(data.toString());}
});
*/// post可以带body数据传到服务器
function http_post(ip, port, url, params, body, callback) {// step1,创建一个 http.ClientRequestvar options {host: 127.0.0.1,port: port,path: url ? params,method: POST,headers: {Content-Type: application/x-www-form-urlencoded,Content-Length: body.length}};var req http.request(options, function(incoming_msg) {console.log(respones status incoming_msg.statusCode);// 监听IncomingMessage的data事件当收到服务器发过来的数据的时候触发这个事件incoming_msg.on(data, function(data) {if (incoming_msg.statusCode 200) {callback(true, data);}});});// step2 写入body数据req.write(body);// 发送请求req.end();
}http_post(127.0.0.1, 6080, /upload, filenamemy_file.txt, Hello Htpp Post, function(is_ok, data) {if (is_ok) {console.log(upload_success, data.toString()); }
});服务器处理Get和Post请求
var path require(path);
var express require(express);
var app express();
// 配置我们的网站的根目录,www_root
app.use(express.static(path.join(process.cwd(), www_root)));
app.listen(6080);// 设置我们的跨域访问
app.all(*, function(req, res, next) {res.header(Access-Control-Allow-Origin, *);res.header(Access-Control-Allow-Headers, X-Requested-With);res.header(Access-Control-Allow-Methods,PUT,POST,GET,DELETE,OPTIONS);res.header(X-Powered-By, 3.2.1)res.header(Content-Type, application/json;charsetutf-8);next();
});
// end// get, 处理响应
app.get(/login, function (request, respones) {console.log(/login comming); // 服务器收到请求后获取客户端get操作参数console.log(request.query);// 服务器回信息给客户端respones.send(SUCCESS);
});app.post(/upload, function(request, respones) {console.log(/upload comming);// 获得url上传来的参数console.log(request.query);// 获得用户给我们发送过来的数据// 监听我们的data来获得request.on(data, function(data) {console.log(data.toString());respones.send(UPLOAD OK); });
});
文件的异步读写
1: 导入fs模块: var fs require(“fs”); 2: 创建一个目录: 异步:fs.mkdir(“路径”, end_func() {}); 同步:fs.mkdirSync(“路径”); 3: fs.existsSync(path),异步的被废弃; 4: fs.rename() 修改文件的名字; 5: 打开一个文件: fs.open/fs.openSync 6: 关闭一个文件: fs.close/fs.closeSync; 7: fs.read/fs.readSync; 8: fs.readFile/fs.readFileSync 异步读文件; 9:fs.readdir/fs.readdirSync 读文件夹数据; 10: fs.write/fs.writeSync 11: fs.writeFile/fs.writeFileSync 写文件;
// 获得我们的fs模块
var fs require(fs);// 等待我们创建好了这个文件夹以后再来执行下一条指令
// fs.mkdirSync(./output);
// 当我们执行这个console.log的时候文件夹已经创建好了这个是同步
// console.log(hello);
/*
if (fs.existsSync(./output)) {console.log(output exist);fs.rename(./output, ./rename_output, function(err) {if (err) {console.log(err);return;}console.log(rename sucess);});
}
else {// 异步fs.mkdir(./output, function(err) {if (err) {console.log(err);return;}// 回掉函数的位置能保证你已经穿件好这个好这个我文件夹。console.log(success);// end }); }// 获取文件信息
/*fs.stat(./hello.txt, function(err, stat) {if (err) {console.log(err);return;}console.log(stat.size);console.log(stat.ctime);
});*/
// end// 同步
var stat fs.statSync(./hello.txt);
console.log(stat.size);
// end// 异步读一个文件
/*fs.readFile(./hello.txt, function(err, file_data) {if (err) {console.log(err);return;}console.log(file_data.toString());
});*/
// end// 同步读一个文件
var file_data fs.readFileSync(./hello.txt);
console.log(file_data);
// end // 打开一个文件
fs.open(./hello.txt, r, function(err, file_handle) {if (err) {console.log(err);return;}// 拿到了访问这个文件的钥匙;文档 里面的fd,文件句柄console.log(open file success);fs.fstat(file_handle, function(err, stat) {var buf Buffer.allocUnsafe(stat.size);// 异步读写把我呢见读入到bufferfs.read(file_handle, buf, 0, stat.size, null, function(err) {fs.close(file_handle); console.log(buf.toString());});});
})
// end // 异步写文件
/*fs.writeFile(./writefile.txt, Hello this write File called!, function(err) {if (err) {console.log(err);return;}console.log(success);
});*/
// end
/*fs.open(./writefile.txt, a, function(err, fd) {fs.write(fd, Hello this write File called!, function(err) {fs.close(fd);});
});
*/var fd fs.openSync(./writefile.txt, a);
fs.writeSync(fd, Hello this write File called!);
fs.closeSync(fd);BASE64、MD5、SHA1编码解码
1:Base64编码的作用由于某些系统中只能使用ASCII字符。Base64就是用来将非ASCII字符的数据转换成ASCII字符的一种方法。 Buffer输出成Base64编码; new Buffer(content).toString(“base64”); Base64编码 解码 new Buffer(content, “base64”).toString();
2: MD5值: 任何数据经过MD5加密后会生成一串16字节的二进制对应的 hex’字符串; var md5 crypto.createHash(‘md5’); md5.update(content); md5.digest(‘hex’);
3: SHA1: 任何数据经过SHA1加密后会生成一串20字节的二进制对应的 hex’字符串 var sha1 crypto.createHash(‘sha1’); sha1.update(content); md5.digest(‘hex’);
base64
var fs require(fs);function base64_encode(content) {var buf new Buffer(content);var base64 buf.toString(base64);return base64;
}function base64_decode(base64_str) {var buf new Buffer(base64_str, base64);return buf;
}// 进一段二进制的数据转成 base64
var base64_str base64_encode([0xff, 0xf1, 0x11, 0x13, 0xf7]);
console.log(base64_str);
// var decode_buf base64_decode(base64_str);
console.log(decode_buf);// 二进制的图片转成文本传送, BASE64编码/解码;
fs.readFile(avator3.png, function(err, data) {if (err) {console.log(err);return;}var img_base64 base64_encode(data);// console.log(img_base64);var img_data base64_decode(img_base64);fs.writeFile(base64_img.png, img_data);
});md5/sha1
hash算法不可逆的不同内容HASH值不同可以用来存放密码,判断两个文件是否相同等
var crypto require(crypto);function md5(data) {var md5 crypto.createHash(md5);md5.update(data);return md5.digest(hex);
}// b4 1c 16 1c 9b 8d 83 e3 42 01 bd 3f 57 b7 33 ca --qidian
var str md5(qidian);
console.log(str);// e10adc3949ba59abbe56e057f20f883e -- 123456
var str2 md5(123456);
console.log(str2);var data fs.readFileSync(avator3.png);
// 84 92 a5 0b 16 95 c5 4d 43 62 12 69 5c f0 fc 52 16个字节的--.Hex
str md5(data);
console.log(str);// 4bde5246df25451af00ecba580bdb581
data fs.readFileSync(base64_img.png);
str md5(data)
console.log(str);
// end// d735871a64133ee062400659cf91b8234d1c1930
function sha1(data) {var sha1 crypto.createHash(sha1);sha1.update(data);return sha1.digest(hex);
}str sha1(HelloWorld!);
console.log(str);
定时器Timer
1: setImmediate: 事件循环的当前回合结束时要调用的函数; 2: setInterval 每隔一段时间调用一次; 3: setTimeout 一段时间后触发这个调用; 4:取消:clearImmediate/clearInterval/clearTimeout;对象都是有set系列的函数返回回来的;
fs.readFile(base64_img.png, function(err, data) {if (err) {return ;}console.log(begin setImmediate);// 等本次事件执行完成后再来掉这里设置的回掉函数setImmediate(function() {console.log(yes setImmediate called);});console.log(end setImmediate);});setTimeout(function(data) {console.log(data);
}, 3000, 12345);var timer setInterval(function(data) { console.log(setInterval called: , data);
}, 3000, Hello);setTimeout(function(data) {clearInterval(timer);
}, 10000, 12345);mysql数据库操作
var mysql require(mysql);// 创建一个连接池我们每次要发送 sql语句给mysql server都通过这个连接池来获得连接对象;
// 连接对象的有效性就有这个池来负责管理;
// 避免mysql在一段时间后没有数据通讯的情况下会自动关闭连接通道var conn_pool mysql.createPool({host: 127.0.0.1, // 数据库服务器的IP地址port: 3306, // my.cnf指定了端口默认的mysql的端口是3306,database: my_database, // 要连接的数据库user: root,password: 123456,
});// callback 1: err, 2, rows, 3, 每个字段的说明
// 异步,执行完后腰等回掉不是马上就有结果。
// 异步的mysql的操作能投提升我们的服务器的吞吐量function mysql_exec(sql, callback) {// getConnection 是从这个连接池里面获得mysql的连接通道,// 异步获取的如果有结果了就会调用一个回掉函数;// err, 是否有错误如果没有错误err null, 如果成功后面conn就是我们连接池// 返回給我们的和mysql server 进行通讯的句柄conn_pool.getConnection(function(err, conn) {if (err) { // 如果有错误信息if(callback) {callback(err, null, null);}return;}// 发送数据库的cmd到mysql server;// query向服务器发送sql语句的命令有返回的话就会调用我们的回掉函数;conn.query(sql, function(sql_err, sql_result, fields_desic) {if (sql_err) {if (callback) {callback(sql_err, null, null);}return;}// sql_result返回给我们的结果// fields_desic 每个字段的描述if (callback) {callback(null, sql_result, fields_desic);}});});
}// select的查询结果就是 [包住结果(1条)]
var sql_cmd select * from uinfo limit 1;
mysql_exec(sql_cmd, function(err, sql_result, fields_desic) {if (err) {return;}if (sql_result) {console.log(sql_result); }
});// end
// update一般不关心结果但是他会给我们回一个我们update的结果的情况。
sql_cmd update uinfo set upwd \777777777\;
mysql_exec(sql_cmd, function(err, sql_result, fields_desic) {if (err) {return;}if (sql_result) {console.log(sql_result); }
});// 插入一条记录
sql_cmd insert into uinfo (uname, upwd) values(\blake\, \98989898\);
mysql_exec(sql_cmd, function(err, sql_result, fields_desic) {console.log(get result);if (err) {console.log(err);return;}if (sql_result) {console.log(sql_result); }
});
redis数据库操作
1:内存数据库,同时也能够保存数据到磁盘; 2: 比其他的内存数据库有着更多的数据类型: 列表,集合,排序集合,哈希表等; 3:主从结构: 数据可以备份到从服务器; 4: Redis数据操作速度快; 5:所有的操作都是原子操作;
哈希表: HMSET key 字段 value 字段 value …; HGETALL key HEXISTS key 字段 HGET key 字段 HKEYS key 返回所有的字段filed HMGET key filed 列表: LPUSH/RPUSH list_name v1 LRANGE list_name start stop LPOP/RPOP list_name 有序集合: --排行 ZADD key 权重 value ZRANGE key start stop ZRANGE key start stop WITHSCORES (显示权重)
var redis require(redis);// 创建一个client连接到了我们的redis server
var client redis.createClient({host: 127.0.0.1,port: 6379,db: 0,
});// 表
// key---value
// set, get
client.set(my_redis_class_key, 123456);
// err, data
client.get(my_redis_class_key, function (err, data) {if (err) {return;}console.log(data);
});
// end // 哈希表, 用户表
client.hmset(00015_redis_class_user, {uname: blake,upwd: 123456,uemail: 1332222qq.com,
}, function(err) {});client.hgetall(00015_redis_class_user, function(err, data) {if (err) {return;}console.log(data);
});client.hget(00015_redis_class_user, uname, function(err, data) {if (err) {return;}console.log(data);
});// end // 列表,数组
client.lpush(0000_1111_7777_data, xiaohong);
client.rpush(0000_1111_7777_data, xiaotian);
client.lpush(0000_1111_7777_data, huangdong);
client.lpush(0000_1111_7777_data, blake);client.lrange(0000_1111_7777_data, 0, 10, function(err, data) {if (err) {return;}console.log(data);
});client.lpop(0000_1111_7777_data, function(err, data) {if (err) {return;}console.log(data);
});
// end // 排行耪的有序集合
client.zadd(0000_1111_rank, 500, blake);
client.zadd(0000_1111_rank, 400, huangdong);
client.zadd(0000_1111_rank, 300, xiaotian);
client.zadd(0000_1111_rank, 100, xiaoming);client.zrange(0000_1111_rank, 0, 10, function(err, data) {if (err) {return;}console.log(data);
});
// end // 事件
// 监听我们的error事件, 当有错误的时候不会终止我们的node.js程序
// 如果链接服务器不上我们会触发自动重连
client.on(error, function(err) {console.log(err);
});client.on(end, function() {});
// end