TCP與UDP


TCP

·TCP(Transmission Control Protocol傳輸控制協議)是一個可靠的面向連接的傳輸層協議

  TCP/IP分層模型分為了七層,在每一層中都包含了一些相對獨立的具體的協議。從上往下分為應用層、表示層、會話層、傳輸層、網絡層,數據鏈路層和物理層。

 

  tcp數據包控制位URG、ACK、PSH、PST、SYN、FIN,對tcp的連接、傳輸和斷開進行指揮。

 

·它可以讓你將數據從一台計算機完整有序的傳輸到另一台計算機,內置機制能夠控制數據包的延遲率及丟包率不會太高

·發送方將數據轉為字節流分成,將數據交給IP層。接收方接收后重新裝配成原始的數據。

  應用層發出請求(數據,有含義的,http等),發出的請求在傳輸層添加TCP控制信息(TCP頭部+數據=>數據段segment),再傳遞給網絡層添加IP頭部標識唯一地址(IP頭部+數據段=>數據包Packet),然后到達數據鏈路層添加MAC頭部及尾部讓兩者的網卡進行通信,之后通過物理層(網線、光纖等)以比特流的形式進行傳輸。到達目標主機之后,由下向上進行解析,在數據鏈路層去除mac頭尾,再向上到達網絡層去掉IP頭部,再向上到達傳輸層去除TCP頭部,最終到達應用層得到數據。

·TCP對字符和字符編碼是完全無知的,不同的編碼會導致傳輸的字節數不同

·TCP使用流控制來確保兩點之間傳輸數據的平衡,以防止快速的發送方淹沒慢速的接收方

·TCP在傳輸前要經過3次握手才能形成會話,只有會話形成后,服務器端和客戶端才能互相發送數據。

  TCP三次握手:第一次握手是主機A向主機B請求建立連接,發送SYN;第二次握手是主機B同意主機A的連接請求,發送SYN、ACK;第三次握手是主機A向主機B發送ACK。

·在會話過程中,服務器和客戶端分別提供一個套接字(socket),這兩個套接字共同形成一個連接。服務器和客戶端通過套接字進行通信

TCP服務器

開發過程中主要控制的是應用層和傳輸層。

net模塊用於實現TCP服務器端和客戶端之間的通信。

    ·options參數:

    -allowHalfOpen:是否允許半開連接。屬性值為false時,TCP服務器收到客戶端的FIN包時會回發FIN包,為true時,服務器收到客戶端FIN包不回發FIN包

    ·connectionListener=function(socket){}客戶端連接時的回調函數

    -socket表示服務器監聽的socket端口對象

  ·返回被創建的服務器server

  ·listen(port,[host],[backlog],[callback])  

    -port監聽的端口號

    -host監聽的IP地址或主機名

    -backlog等待隊列中的最大數量(默認511)

創建一個tcpserver.js

var net = require('net'); var util = require('util'); //net.Socket 雙工流 Duplux
var server = net.createServer({allowHalfOpen:true},function(socket){ console.log(util.inspect(socket.address())); //查看當前連接數量
  server.getConnections(function(err,count){ console.log(count); }); socket.on('error',function(err){//監聽客戶端的錯誤
 console.log(err); socket.destroy(); });   socket.setEncoding('utf8');//可讀流的方法
   socket.on('data',function(data){     console.log(data);    })    socket.on('close',function(err){//end事件與close事件的區別是:close一定會觸發,end則不一定觸發
 console.log(err); socket.destroy(); }) }) server.on('error',function(err){//監聽服務器端的錯誤
 console.log(err); }); server.listen(8089,function(){ console.log(util.inspect(server.address())); setTimeout(function(){ server.close();//客戶端全都斷開后才會關閉服務端
    },3000) }); server.on('close',function(err){ console.log('服務器端正常關閉'); });

寫一個tcpSocket.js

var net = require('net'); var util = require('util'); var fs = require('fs'); //net.Socket 雙工流 Duplux
var ws = fs.createWriteStream('./socket.txt'); var server = net.createServer({allowHalfOpen:true},function(socket){ socket.setTimeout(10*1000); socket.on('timeout',function(){ socket.resume(); socket.pipe(ws,{end:false}); ws.write(socket.remoteAddress) }); }) server.on('error',function(err){ console.log(err); }); server.listen(8089,function(){ console.log(util.inspect(server.address())); });

 socket

  ·net.socket代表一個socket端口對象

  ·socket端口對象可用來讀取客戶端發送的流數據,讀到數據時觸發data事件

    -socket.on('data',function(){})

  ·創建socket: var socket = new net.Socket([options])

    -options

      -fd socket文件描述符

      -type 客戶端協議,tcp4或tcp6

      -allowHalfOpen是否允許半開連接

  .連接TCP服務器:socket.connect(port,[host],[connectListener])

    -port 端口

    -host主機地址

    -connectListener 連接成功后的監聽

  ·向服務器發送數據:socket.write(data,[encoding],[callback])

    -data 寫入的數據

    -encoding 編碼

 創建一個tcpClient.js

var net = require('net'); var util = require('util'); var socket = new net.Socket({allowHalfOpen:true}); socket.setEncoding('utf8'); socket.connect(8089,'localhost',function(){ socket.write('hello');//客戶端向服務端發送數據 socket.on('data',function(data){//客戶端接收來自服務器的方法 console.log(data); }); });

 net類方法

  ·net.isIP 判斷字符串是否是IP

  ·net.isIPv4 是否是IPv4地址

  ·net.isIPv6 是否IPv6地址

UDP

  tcp是基於連接的協議,進行通信前客戶端與服務器要先建立連接。UDP是面向非連接的協議,可能直接發數據包

  UDP不要求分組順序到達傳輸層中

  受網絡影響可能丟失數據包

  資源消耗少,處理速度快,適合音頻、視頻和普通數據傳輸

  UDP協議中的包成為數據報datagram

  UDP協議不區分客戶端和服務端的概念,都可以創建socket對象

    ·var socket = dgram.createSocket(type,[callback])

      ·type 協議類型可以是udp4或udp6

      ·callback = function(msg,rinfo)收到數據時的回調函數

        -msg收到的數據

        -rinfo

          -address 發送者的IP

          -family 地址類型

          -port發送者的socket端口號

          -size發送者發送的數據字節數

    ·綁定地址和端口  socket.bind(port,[address],[callback])

    ·發送數據 socket.send(buf,offset,length,port,address,[callback])

      -buf 要發送的數據buffer

      -offset從緩存區中第幾個字節開始發送數據

      -length發送數據的字節數

      -port接收數據的端口號

      -address 接收數據的IP地址

      -callback function(err,bytes){}發送完畢時所調的回調函數

        -err 發送出錯時觸發的錯誤對象

        -bytes發送數據的字節數

創建一個udpServer.js

var dgram = require('dgram'); var socket = dgram.createSocket('udp4'); socket.on('message',function(msg,rinfo){ console.log(msg.toString()); console.log(rinfo); socket.send(msg,0,msg.length,rinfo.port,rinfo.address); }); socket.bind(41234,'localhost');

創建一個udpClient.js

var dgram = require('dgram'); var socket = dgram.createSocket('udp4'); socket.on('message',function(msg,rinfo){ console.log(msg.toString()); console.log(rinfo); }); socket.send(new Buffer('珠峰培訓'),0,6,41234,'localhost',function(err,bytes){ console.log('發送了個%d字節',bytes); }); socket.on('error',function(err){ console.error(err); });

 創建一個即時通訊的tcp聊天chatServer.js

/** * 1.創建一個服務器 * 2. 客戶端可以連接服務器 * 3.客戶端可以發言,然后廣播給大家 * 4.客戶端連接和退出后都要通知大家。 * 5.顯示當前的在線人數 */
var net = require('net'); var util = require('util'); var clients = {}; var server = net.createServer(function(socket){ var nickname; socket.setEncoding('utf8'); server.getConnections(function(err,count){ socket.write('歡迎光臨,當前在線'+count+'人,請輸入用戶名\r\n>'); }); socket.on('data',function(data){ //console.log(new Buffer(data));
   data = data.replace(/\r\n/,''); if(nickname){ broadcast(nickname,nickname+":"+data+'\r\n'); }else{ nickname = data; clients[nickname] = socket; broadcast(nickname,nickname+'加入了聊天室\r\n'); } }); socket.on('end',function(){ broadcast(nickname,nickname+'離開了聊天室\r\n'); clients[nickname].destroy(); delete clients[nickname]; }); socket.on('error',function(){ }); socket.on('close',function(){ }); }) function broadcast(nickname,msg){ for(var name in clients){ if(nickname != name) clients[name].write(msg); } } server.listen(8088);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM