TCP/IP协议 简介

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

      

   

      


猜你喜欢

转载自www.cnblogs.com/dalun101/p/9367804.html