读<了不起的Node.js>-08.TCP协议

传输控制协议(TCP)

  • TCP 是一个面向连接的协议,它保证了两台计算机之间的数据传输的可靠性,和顺序
  • 简而言之,TCP是一种传输层协议,他可以让你将数据从一台计算机完整有序的传输到另一台计算机
  • HTTP协议基于TCP协议
  • 我们来了解TCP/IP协议

Node HTTP服务器是构构建于 Node TCP服务器之上的,编程角度解释就是node中得http.Server 继承自 net.Server(not是TCP模块)

  • 多多了解tcp 以及如何使用相关node api对书写和理解网络程序会大有裨益

TCP的特点

  • 如若只是使用,无需甚解

  • 理解这些有利于分析高层的协议和服务器,例如 web服务器,数据库等

  • 面向连接是首要特性

面向连接的通信和保证顺序的传递

  • image

面向字节

  • TCP允许数据以ASCII字符或者Unicode进行传输(前者为每个字符一个字节,后者为每个字符四个字节)

可靠性

  • TCP本身是不可靠的服务
  • 所以当数据发送出去后,发送者就会等待一个确认消息(表示数据包已经收到的简短的确认消息),如果超时,还未收到确认消息.发送方就会对数据进行重发
  • 这种机制有效的解决了如网络错误或者网络阻塞这样的不可预测的情况
  • 扩展:TCP协议为什么可靠-季白白白

流控制

  • TCP会通过一种叫做流控制的方式来确保两点之间传输数据的平衡(避免出现传输速度不一致)

拥堵控制

  • TCP有一种内置机构能够控制数据包的延迟率以及丢包率不会太高,以此来确保 服务的质量(Qos)
  • TCP会通过控制数据包的传输速率来避免拥堵的情况

Telnet

  • Telnet是一个早期的网络协议,旨在提供双向的怒你终端,在SSH出现以前,它作为一种控制远程计算机的方式被广泛使用,它是TCP协议的上层的协议
  • 下面我们用telnet调用一下web服务器
  • 编写一串代码开启个服务
require('http').createServer(function (req, res) {
    res.writeHeader(200, {'content-type': 'text/html'});
    res.end('<h1>Hello World</h1>')
}).listen(3000);

  • 直接访问本地3000端口可以看见

  • image
  • 我们用telnet来运行这个

  • 这里实验没有成功,,尴尬...

    -
    image.png
  • image.png
  • 这里总结一下

    • 成功创建一个TCP连接
    • 创建了一个HTTP请求
    • 接收到一个HTTP相应,
    • 测试了一些TCP的特性,到达的数据和nodejs中写的一样先谢了响应头.Content-Type,然后是响应体,最后所有的消息都按顺序到达

鉴于没有用telnet实验成功就直接用浏览器了- -!!!

基于Tcp的聊天程序

创建模块

  • 创建项目目录 而后创建package.json文件
  • npm install 测试

理解NET.SERVER- API

  • 创建一个 index.js 文件
const net = require('net');

/*
* 创建服务器
* */

let server = net.createServer(function (conn) {
    //处理连接
    console.log('\033[95m   新建连接!  \033[39m');
});

/*
* 监听
* */

server.listen(3000,function () {
    console.log('\033[96m 服务器端口:3000 \033[39m');
});

  • 这里createServer指定了一个回调函数,每次有新链接的时候都会被执行
  • creatServer回调函数会接收一个对象,该对象是node中一个很常见的实例.流(stream),本例中 它传递的是net.stream 该对象通常是既可读又可写
  • 注意listen

接收连接

  • 我们在回调函数外部添加一个计数器

    -
    image-png
  • 接着我们修改回调函数内容,把计数器递增和打印出欢迎的逻辑添加上去
let server = net.createServer(function (conn) {
    //处理连接
    console.log('\033[95m   新建连接!  \033[39m');
    conn.write(
        '\n > welcome to \033[95m   Node-Chat!  \033[39m' +
        '\n > '+count + 'other people are connected at this time' +
        '\n > please write your name and press enter'
    );
    count++;
});
  • 这里我们用telnet连接测试
    直接打印出我们所需要展示的内容(我已经登录四次了 所以数字是 3)

-
image.png
  • 当底层套接字关闭时,nodejs 会触发close时间,nodejs中有另个和连接种子相关的时间见end和close,前者是当客户端显示关闭tcp拦截是触发,例如当你关闭telnet是 他会发送一个名为FIN的包给服务器,意味着结束连接
  • 当连接发生错误时(触发error事件),end事件不会触发,因为服务器端并未接收到FIN包信息,不过这两种情况下,close事件都会触发,所以上述例子使用close事件比较好

-
image.png

data事件

  • 下面我们处理客户端发送的数据
  • 监听data事件,net.Stream是一个事件触发器 EventEmitter
let server = net.createServer(function (conn) {
    //处理连接
    console.log('\033[95m   新建连接!  \033[39m');
    conn.write(
        '\n > welcome to \033[95m   Node-Chat!  \033[39m' +
        '\n > '+count + 'other people are connected at this time' +
        '\n > please write your name and press enter'
    );
    count++;
    conn.on('data',function (data) {
        console.log(data);
    });
    conn.on('close',function () {
        count--;
    })
});
  • 我们启动服务器,启用客户端
  • image.png
  • 当进行输入的时候我们发现,打印出来一串二进制字节码

  • image.png
  • 这里我们在creatServer回调里面添加一句conn.setEncoding('utf8')

    image.png

  • 这样就可以在控制台打印了

状态以及记录连接的情况

  • 此前定义的计数器通常称为状态,在本例中不同连接的用户需要修改同一个状态变量,这个在Node中称为共享状态的并发
  • 为了实现这点,我们需要对该状态金星 扩展,来追踪究竟谁连接进来
  • 首先我们记录设置昵称的用户
const net = require('net');

/*
* 计数器
* */
let count = 0,users={};
/*
* 创建服务器
* */

let server = net.createServer(function (conn) {
    //对二进制进行转码
    conn.setEncoding('utf8');
    //设置当前连接昵称
    let nickname;

    //抽取方法
    function broadcast(msg, exceptMyself){
        for (let i in users){
            if (!exceptMyself || i!=nickname){
                users[i].write(msg);
            }
        }
    }

    //处理连接
    console.log('\033[95m   新建连接!  \033[39m');
    conn.write(
        '\n > welcome to    Node-Chat!  ' +
        '\n > '+count + '   other people are connected at this time' +
        '\n > please write your name and press enter: '
    );
    count++;
    conn.on('data',function (data) {
        //删除回车符
        data = data.replace('\r\n', '');
        //接收到的第一份数据应当是用户的昵称
        if (!nickname){
            if (users[data]){
                conn.write(' > nickname already in use,try again:');
                return;
            }else{
                nickname=data;
                users[nickname] = conn;
                // for (let i in users) {
                //     users[i].write(' > ' +nickname + 'joined the room!! \n')
                // }
                broadcast(''+nickname+'joined the room! \n');
            }
        }else{
            //视为聊天记录
            // for (let i in users){
                //这里用来确保消息只发送给除了自己以外的其他客户端
                // if (i != nickname){
                //     users[i].write(' > ' + nickname + ':' + data + '\n');
                // }
                broadcast(nickname + ': ' + data+'\n', true);
            // }
        }
    });



    conn.on('close',function () {
        count--;
        //当有人离开时我们需要清除users数组中对应的元素
        delete users[nickname]
        broadcast('' + nickname + 'left the room! \n');
    })
});

/*
* 监听
* */

server.listen(23,function () {
    console.log('\033[96m 服务器端口:3000 \033[39m');
});


  • 这是完整版的 简单的实现了 开启一个服务器 登录客户端实现交流
  • image.png
  • image.png
  • image.png
  • 最后在退出的时候逻辑应该是有问题的 一个退出就崩了....

能力不足,还得再看看

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容