1. 程式人生 > >TCP/IP協議 簡介

TCP/IP協議 簡介

sele 如何 xxx 簡介 server dad ping 用戶數 事件

TCP/IP協議

一、層次劃分:

  層次:鏈路層==>網絡層==>傳輸層==>應用層
  理論層次:物理層==>數據鏈路層==>網絡層==>傳輸層==>會話層==>表示層==>應用層
  應用層:解決要傳遞什麽數據
  傳輸層:解決如何傳輸數據,udp/tcp
  網絡層:解決地址問題,IP
  鏈路層:具體傳輸工具

二、UDP(用戶數據包協議),註重速度,不夠穩定

  #創建客戶端從服務器上下載文件

  #coding=utf-8

  from socket import *
  import struct
  import sys

  if len(sys.argv) != 2:
    print(‘-‘*30)
    print("tips:")
    print("python xxxx.py 192.168.1.1")
    print(‘-‘*30)
    exit()
  else:
    ip = sys.argv[1]

  # 創建udp套接字
  udpSocket = socket(AF_INET, SOCK_DGRAM)

  #構造下載請求數據
  cmd_buf = struct.pack("!H8sb5sb",1,"test.jpg",0,"octet",0)

  #發送下載文件請求數據到指定服務器
  sendAddr = (ip, 69)
  udpSocket.sendto(cmd_buf, sendAddr)

  p_num = 0

  recvFile = ‘‘

  while True:
    recvData,recvAddr = udpSocket.recvfrom(1024)
    recvDataLen = len(recvData)

    cmdTuple = struct.unpack("!HH", recvData[:4])

    #得到操作號與數據包編號
    cmd = cmdTuple[0]
    currentPackNum = cmdTuple[1]

    if cmd == 3: #是否為數據包

      # 如果是第一次接收到數據,那麽就創建文件
      if currentPackNum == 1:
        recvFile = open("test.jpg", "a")

      # 包編號是否和上次相等
      if p_num+1 == currentPackNum:
        recvFile.write(recvData[4:]);
        p_num +=1
        print ‘(%d)次接收到的數據‘%(p_num)

        ackBuf = struct.pack("!HH",4,p_num)
        udpSocket.sendto(ackBuf, recvAddr)
      # 如果收到的數據小於516則認為出錯
      if recvDataLen<516:
        recvFile.close()
        print ‘已經成功下載!!!‘
        break

    elif cmd == 5: #是否為錯誤應答
      print "error num:%d"%currentPackNum
      break

  udpSocket.close()

  UDP廣播(只有udp能用)

    import socket
    dest = (‘<broadcast>‘,端口號)
    s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    #使用廣播時固定調用這句話
    s.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
    s.sendto(‘hi‘,dest)

三、TCP(傳輸控制協議)

  數據傳輸穩定,略慢於udp,web 服務器都是使用tcp

  1、tcp服務器
  from socket import *

  serverSocket = socket(AF_INET,SOCK_STREAM)
  serverSocket.bind((‘‘,7788))
  serverSocket.listen(5)
  #accept()返回值是一個元組
  #clientSocket 表示這個新的客戶端
  #clientInfo 表示新客戶端的IP和port
  clientSocket,clientInfo = serverSocket.accept()

  recvData = clientSocket.recv(1024)
  print(‘%s:%s‘%(str(clientInfo),recvData))

  clientSocket.close()
  serverSocket.close()

  2、tcp客戶端
  manSocket = socket(AF_INET,SOCK_STREAM)
  manSocker.connect((‘客戶端IP‘,4567))
  sendData = imput(‘請輸入要傳輸的信息:‘)
  #tcp已經鏈接好了服務器,所以發數據不用再寫IP和port
  #udp因為沒有事先鏈接,所以每次發送都要寫IP和port
  manSocker.send(sendData.encode(‘gb2312‘))
  recvData = manSocker.recv(1024)
  print(‘recvData:%s‘%recvData.decode(‘gb2312‘))
  manSocker.close()


  3、單進程服務器完成偽並發

  #select,最多1024個元素,用輪詢方式檢測
  #poll,解決了套接字上限的問題,輪詢方式檢測
  #epoll,沒有上限,事件通知機制
  from socket import *
  import select

  server = socket(AF_INET,SOCK_STREAM)
  server.bind((‘‘,7788))
  server.listen(1000)

  list = [server]

  while True:
    #linux 中,select通過底層直接分別篩選三個列表,篩選條件分別為可接收數據,可發送數據,有異常信息
    #沒有更新信息時默認堵塞,有新客戶訪問或已有客戶發信息時解堵塞
    recvableList,list2,list3 = select.select(list,[],[])

    for i in recvableList:
      #有新的客戶端訪問時,服務端創建新的socket,並放入列表,等待下次循環篩選
      if i == server:
        newSocket,socketAddr = server.accept()
        list.append(newSocket)

      #客戶發送信息時,讀取發送的數據
      else:
        recvData = i.recv(1024)
        if recvData:
          i.send(recvData)
        else:
          #此時客戶端close(),下面移除select監聽的i這個socket
          list.remove(i)
          i.close()

  4、其他備註:

    a. ip地址和網絡掩碼按位與操作後,得到網絡號,網絡號相同則能夠相互通信

    b. MAC地址,即網卡實際地址,由6個字節的十六進制數(12位)組成,前三字節表示生產廠家,後三位表示生產編號

    c. icmp:ping一個電腦

    d. arp:根據IP獲取一個電腦上的網卡號,就是Mac地址

    e. rarp:根據Mac地址找IP

      技術分享圖片

  

      技術分享圖片


技術分享圖片

TCP/IP協議 簡介