node重要API之NET——TCP编程之旅

废话:最近去了一趟上海会了会一个程序员朋友,途径SNH48握手会,说好我就去看看,没想到握手了王诗蒙,掉入巨坑:塞纳河。回来后边听着《春夏秋冬》,边学习用node.js写了一个基于TCP的简易聊天室服务端案例。

基本网络知识

目前的互联网共有七层,自下而上分别是:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。这七层从前往后是从底层到高层设计的,层层封装,每经过一层都会添加自己层的报头,对于普通程序员来说所能接触的其实就是第七层——应用层。说起应用层我们所知道的依然甚少,SSH,FTP,HTTP,SMTP就是属于应用层,从模型上说,他们都继承自TCP,都是对TCP封装扩展加强后运用于不同领域的应用服务。

了解七层协议关系可参考:http://blog.csdn.net/qq_33044095/article/details/52754295

早期的Telnet协议更加接近TCP,他能将非telnet服务器的连接(比如http)降级为纯TCP模式。

基于Telnet客户端使用node.js开发一个基于TCP的telnet的服务端,建立一个聊天室应用。

需要使用的API——NET模块介绍

node.js的net模块可以理解为TCP基本模块,与http不同,他是更加基础更加底层的模块。

引入模块:

var net = require("net");

创建服务:

net.createServer(function(conn){
//连接后做什么...
});

注意上述代码在node中,只要客户端请求一次就会执行一次,并且创建一个连接传送给回调函数(这很重要),每一个连接都会存在于内存中,最好在一个外部作用域的数组或者对象中保存这些引用(后面开发聊天室会提到)。

事件:

conn.on("事件名",func);

事件名:data,end,close。

end只能在用户离开关闭连接时触发,如果发生了网络错误是不触发的

close则只要断开都会触发,更为合适!

重点是data事件——接收客户端数据:

  1. 用户发送数据后,node接收到就会触发该事件
  2. 特别注意,telnet在用户每按下一个字符(键盘上的键位)就会发送一次,都触发data事件!

上面的第二点很是麻烦,这会导致绑定在data事件上的function在用户按下键盘后就执行,后面代码中讲述如何解决telnet按下就发送的问题。

写回:

向客户端返回数据使用:

conn.write();

聊天室需求说明

  • Telnet连接上服务器后返回欢迎信息,并要求输入用户名,告诉用户当前多少人在线
  • 输入用户名后连接完成,聊天中显示消息来自的用户名
  • 输入消息后按回车键发送给聊天室其他用户看

值得注意的是:如何解决回车发送:用户名,消息?因为Telnet会在用户每按下一次键盘发送一次数据,就好像用键盘控制你自己电脑一样每一次输入都有反馈事件!

《了不起的node.js》一书中并没有对此进行解释,该书代码不完成,使用将会导致按一次发送一次的问题。

后面代码中提供解决办法!

package.json

{
"name":"chat-serv",
"version":"1.0",
"description":"a chat server based on node and TCP/IP"
}

代码

var tcp = require("net");
//users存储在线用户,键为nickname,值为conn引用
var users = {};
var count = 0;
//每一次telnet请求都会生成一个conn
tcp.createServer(function(conn){
console.log("New connection come in!")
conn.write("\r\n > Welcome to char-serv on node.js!\r\n > "+count+" people are in the room! \r\n > Plese type a nickname for this session(press enter to submit): ");
count++;
conn.setEncoding("utf8");
var nickname = null;
var line="";//一行字符串(按下回车键)
conn.on("data",function(data){
//由于telnet每次输入一个字符都会上传到服务器,对回车进行判断
if(data == "\r\n"){
//如果没有nickname则视为第一次进入,让设置nickname
//else就视为消息
if(!nickname){
//已存在
if(users[line]) {
conn.write("\r\nThe nickname "+line+" has already existed, try another:");
line = "";//清空之前输入的字符
return;
}
//空名字
if(line == ""){
conn.write("\r\nYou can't use empty nickname! Try another:");
return; }
nickname = line;
users[nickname] = conn;
broadcast("\r\nUser["+nickname+"] has joined in!",false);
line="";
}else{
broadcast("\r\n["+nickname+"]: "+line,true,nickname);
line="";
}
}else{
line+=data;//不是回车则补到字符串中
}
});
conn.on("close",function(){
broadcast("User["+nickname+"] has leaved the room!\r\n",true,nickname);
count--;//计数减一
delete users[nickname];//删除连接引用
});
}).listen(3000,function(){
console.log("The server listen on port 3000");
});
/*
* 参数:
* mes:消息
* excSelf:是否除去本人为false
* nickname:当前连接者的昵称,作为key主键
*/
function broadcast(mes,excSelf,nickname){
for(var i in users){
if(!excSelf || nickname != i)
users[i].write(mes+"\r\n");
}
}

分析

变量分析:

count:保存连接数目。

users:对象数组,以用户名为键,以连接引用为值,保存连接引用,主要用于循环推送消息给其他用户,使得消息可以共享。

解决输入即触发data事件问题

很简单:

  1. 建立一个新变量line,合并用户每一次发送的单个字符。
  2. 每一次data事件触发都检测输入是否为"\r\n",也就是windows下的回车键,只有当输入为回车键时才broadcast。

如何判断用户刚刚连接进入?

nickname设置为空,nickname的作用范围应该在当前连接下,所以放在createServer里。当nickname为空说明这个连接刚建立要求用户输入用户名,在判断为回车按下后设置为用户名;当nickname不是空的时候则将接受的数据合并作为聊天消息广播到聊天室中。

效果

将js进行到底:node学习3的更多相关文章

  1. 【特别推荐】Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  2. Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  3. Node.js环境搭建和学习(windwos环境)

    Node.js环境搭建和学习 一.环境搭建 1.下载安装文件 下载地址http://nodejs-org.qiniudn.com/下载Node.js环境安装包,根据操作系统下载对应的安装包 下载地址 ...

  4. node 学习笔记 - Modules 模块加载系统 (1)

    本文同步自我的个人博客:http://www.52cik.com/2015/12/11/learn-node-modules-path.html 用了这么久的 require,但却没有系统的学习过 n ...

  5. [学姿势]实验室搬砖+node学习

    这周开始进行收尾工作,我当然没有进行核心技术的开发,主要负责的是对web端进行展示上的修修补补,主要包括添加VLC播放器.rtsp视频流以及一些js细节. 1.VLC 全称为Video Lan Cli ...

  6. 2015第40周二Node学习

    node历史 今天看cnode开源项目用了io.js,在查这个项目时发现这篇文章node历史,node.js和io.js关系谈到Node.js的由来,不可避免要聊到它的创始人Ryan Dahl.在20 ...

  7. 2015第40周一Node学习

    node学习尝试 早上看了张丹大牛博客文章nodeJS学习路线图和node从零入门系列,感觉获益匪浅,尝试了里面几项内容,对node有了更深入的认识. npm npm是一个node包管理和分发工具,已 ...

  8. Node学习——开篇

    前言:自从下决心转学前端以来,我的专业课java基本荒废了,所以对于后台开发的逻辑也已基本忘干净了.但是作为一名准前端程序猿,我认为还是有必要了解后端开发的,虽不必深入学习,但是能够了解项目从前端到后 ...

  9. node 学习资料

    Node 学习资料: 资料名称 网址 Node.js 中文API文档 http://nodejs.cn/api/ Node 菜鸟教程 http://www.runoob.com/nodejs/node ...

  10. Node学习HTTP模块(HTTP 服务器与客户端)

    Node学习HTTP模块(HTTP 服务器与客户端) Node.js 标准库提供了 http 模块,其中封装了一个高效的 HTTP 服务器和一个简易的HTTP 客户端.http.Server 是一个基 ...

随机推荐

  1. PAT Basic 1020 ⽉饼 (25) [贪⼼算法]

    题目 ⽉饼是中国⼈在中秋佳节时吃的⼀种传统⻝品,不同地区有许多不同⻛味的⽉饼.现给定所有种类⽉饼的库存量.总售价.以及市场的最⼤需求量,请你计算可以获得的最⼤收益是多少. 注意:销售时允许取出⼀部分库 ...

  2. memcached redis 本质区别是功能多少

    功能: 1.memcached 数据类型比较单一,数据淘汰策略单一,功能简单 2.redis 数据类型比较全面, 数据淘汰策略比较多,功能较强 有持久化能力,可以持久存储少量数据(数据量不会大于本机内 ...

  3. 获取文件MD5值(JS、JAVA)

    文章HTML代码翻译于地址:https://www.cnblogs.com/linyihai/p/7040786.html           文件MD5有啥用?                  文 ...

  4. Linux中PATH、 LIBRARY_PATH、 LD_LIBRARY_PATH和ROS_PACKAGE_PATH

    PATH 保存可执行文件程序路径,我们命令行中每一句能运行的命令都是系统先通过PATH来找到命令执行文件所在的位置,再运行这个命令. 实验:执行echo $PATH 能看到当前环境PATH都是配置了哪 ...

  5. 天大IPv6使用指南(老校区)

    天津大学是CERNET地区网络中心和地区主结点之一,提供良好的IPv6服务,在老校区最大接入宽带达到100Mbps,下载资源非常方便. 但是,在天大使用IPv6时,同学们是不是经常出现时断时续的现象呢 ...

  6. vue2.0+mintui+hbuilder 打包移动端app之后出现空白页面的解决方案

    1.首先使用的是vue-cli构建的页面,用hbuildX打包成移动端的安装包(hbuildX打包成app的流程,请看自行搜索) 2.cnpm install build 生成dist文件夹,里面包含 ...

  7. uboot 编译

    . 解包u-boot源码包(u-boot-2016.07) . 配置交叉编译器 根据内核编译里的步骤配置 . 编译uboot yum install ncurses* // ncurses是个终端的图 ...

  8. springboot集成aop日志

    日常开发中假如是前后端完全分离,我们会习惯用浏览器去调用controller的接口来测试.这一个过程普通的日志功能会记录sql参数等一些基本信息.但是假如项目越来越庞大,我们的包越来越多,在维护项目和 ...

  9. SAP PM:通过接口获取设备资产基本信息

    在SAP工厂维护模块中,给设备贴二维码标签是现在越来越流行的做法.因此通过扫描二维码获取设备资产信息是个非常基本的需求. 以下实例简单实现了,给SAP RFC传入设备编码获取设备资产基本信息的需求. ...

  10. 48)PHP,工厂模式

    为啥需要工厂模式啊: (原来是生产类的工具——————————) 工厂类的代码格式: <?php class factory{ //Instance表示“实例”,“对象” static func ...