从入门到自闭之--网络编程

概念:

  1. C/S架构:

    1. C:client 客户端
    2. S: server 服务端,为所有的用户提供服务
  2. B/S架构:只要在浏览器输入网址就可以直接使用了

    1. B:browser 浏览器
    2. S: server 服务端
  3. B/S更好:更节省资源,不用更新,不依赖环境,

    • 统一了所有的web程序入口
  4. C/S架构:安全性,程序比较庞大

mac地址:

​ 是一个物理地址,在网卡中存在的,唯一的标识你的网络设备

  1. mac IP地址:定位到一台机器
  2. port 端口:0-65535,标识一台机器上的一个服务
  3. IP+ port 能够唯一标识一台设备

ip地址:

  1. 是一个逻辑地址
  2. 是可以根据你的位置变化发生改变的
  3. 能够在广域网中快速的定位你
  4. 几个特殊IP
    1. 127.0.0.1 本地回环地址
    2. 0.0.0.0 表示你的所有网卡地址,标识本机回环地址+内网地址+公网地址

公网和内网

  1. 公网ip:你能够在任意一个地方去访问的ip地址(不包含保留字段)
    1. ip v4:4位点分十进制组成0.0.0.0~255.255.255.255
    2. IP v6:6位冒分十六进制0:0:0:0:0:0~FFFF:FFFF:FFFF:FFFF:FFFF:FFFF
  2. 内网:只能在一个区域内使用,除了这个区域就无法使用
    1. 所有的内网ip都要使用保留字段
    2. 192.168.0.0--192.168.255.255
    3. 10.0.0.0-10.255.255.255
    4. 172.16.0.0-172.31.255.255

路由器和交换机:

  1. 交换机:完成局域网内通信

    • 通过ip找mac地址:arp协议,只用到广播和单播

  • 广播
  • 单播
  • 组播
  1. 路由器:完成局域网间通信(网关)

    1. 网关:所有与局域网外部通信的时候所过的关口,所有的请求都会在这里换上网关IP对外通信
  2. 子网掩码(了解):255.255.255.0

    • ip 和子网掩码 按位于运算(0或者1)
    • 可以判断要寻找的机器是不是在一个局域网中
  3. 端口号:

    3306  mysql 数据库
    6379  redis端口
    5000  flask端口
    

TCP实时通信

##server

import socket

sk = socket.socket()
sk.bind(("127.0.0.1",9043))
sk.listen()
conn,addr = sk.accept()
conn.send(b'hi')
msg = conn.recv(1024).decode("utf-8")
print(msg)
conn.close()
sk.close()
```Python
##client

import socket

sk = socket.socket()

sk.connect(("127.0.0.1",9043))

msg = sk.recv(1024).decode("utf-8")
print(msg)
sk.send("傻子".encode("utf-8"))
sk.close()
```

网络概念补充:

  1. osi七层协议

    1. 应用层
    2. 表示层
    3. 会话层
    4. 传输层
    5. 网络层
    6. 数据链路层
    7. 物理层
  2. osi五层协议:

    1. 应用层
    2. 传输层 #端口 TCP/UDP
    3. 网络层 # IP 路由器
    4. 数据链路层 # mac,arp协议,网卡和交换机
    5. 物理层

  1. TCP/IP--网络层arp

TCP:

​ 上传,下载,邮件,可靠,面向连接,速度慢,能传递的数据长度不限

  1. 两边需要先连接

    • 三次握手

      第一次握手:Client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
      第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
      第三次握手:Client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

  2. 消息传递:(主要看发送,连接时的状态)

  3. 断开连接

    • 四次挥手

      (第一次挥手
      当客户端向服务端请求断开,这时会发送fin的标记报文。
      第二次挥手
      当服务端收到客户端fin断开报文时候,可能正在处理数据,此时服务端会发生ack报文。
      第三次挥手
      当服务端处理完成后,会再次向客户端发送FIN报文,此时可以断开连接。
      第四次挥手
      当客户端收到服务端的fin报文,会向服务端发送确认ACK,经过两个msl《Maximum Segment Lifetime》时长后断开连接。)

UDP:

​ 即时通讯软件,不可靠,面向数据报,速度快,能传递的数据长度有限

1. 支持一对一,一对多,多对多

粘包:

​ 当多条消息发送时接受变成了一条或者出现接收不准确的情况

  1. 粘包现象会发生在发送端

    1. 两条或多条消息间隔时间短,长度短,就会把两条消息在发送之前就拼在一起
    2. 节省每一次发送消息回复的网络资源
  2. 粘包现象会发生在接收端

    1. 多条消息发送到缓存端,但没有被及时接收,或者接收的长度不足一次发送的长度
    2. 数据与数据之间没有边界
  3. 本质:发送的每一条数据之间没有边界

  4. 步骤:

    1. 计算要发送的数据字节长度

    2. 把字结的长度变成4字节,借助struct

          1. 计算要发送的数据字节长度
          2. 把字节的长度变成4字节
          3. 发送这4个字节
          4. 发送数据
      
      1. 服务端

  1. 客户端:

  1. 验证客户端的合法性:

    1. 客户端:
    import socket
    import hashlib
    SECRET_KEY = b'alexbigs'
    
    def check_client():
        randbytes = sk.recv(32)
        md5 = hashlib.md5(SECRET_KEY)
        md5.update(randbytes)
        code = md5.hexdigest().encode('utf-8')
        sk.send(code)
    sk = socket.socket()
    sk.connect(('127.0.0.1',9001))
    check_client()
    print('正常的客户端通信')
    
    1. 服务端:
    import os
    import socket
    import hashlib
    SECRET_KEY = b'alexbigsb'
    
    def check_client(conn):
        randbytes = os.urandom(32)
        conn.send(randbytes)
    
        md5 = hashlib.md5(SECRET_KEY)
        md5.update(randbytes)
        code = md5.hexdigest()
        code_cli = conn.recv(32).decode('utf-8')
        return code == code_cli
    
    sk = socket.socket()
    sk.bind(('127.0.0.1',9001))
    sk.listen()
    while True:
        conn,addr = sk.accept()
        if not check_client(conn):continue
        print('进程正常的通信了')
    
    # import os
    # import hmac  # hashlib==hmac
    # randbytes = os.urandom(32)
    # mac = hmac.new(SECRET_KEY,randbytes)
    # ret = mac.digest()
    # print(ret)
    
  2. 并发的socket

    1. 模块socketserver -- 上层模块.

      客户端
      import socket
      
      sk = socket.socket()
      sk.connect(('127.0.0.1',9001))
      
      while True:
          ret = sk.recv(1024)
          print(ret)
      
      import time
      import socket
      
      sk = socket.socket()
      sk.bind(('127.0.0.1',9001))
      sk.listen()
      
      while True:
          conn,addr = sk.accept()
          n = 0
          while True:
              conn.send(str(n).encode('utf-8'))
              n+=1
              time.sleep(0.5)
      
原文地址:https://www.cnblogs.com/heyulong1214/p/12069949.html