网络基础知识

网络基础知识

osi 七层协议

image-20200813153850827
# 此处特别说明,在数据链路层传输时,分为在局域网类和在非局域网类,(通过ip和子网掩码进行and预算 可以得出是否两个ip处于同一个局域网类)都是用mac地址找寻,在局域网类,用广播,在非局域网类,要先通过网关的ip和mac地址传输出去,通过arp协议,将目标的mac地址拿到,然后正式发送数据的时候携带目标ip和网关的mac出网关(网关有两个地址,一个是对局域网内的,一个对外的)
# osi七层协议时arp协议时属于数据数据链路层,tcp/ip五层协议时属于网路层

tcpudp协议

image-20200813155221222
# 此处特别说明 tcp协议比udp协议安全的关键点,因为tcp中会等数据发送完毕,确认对方收到才会删除本地的文件,而udp无论对方是否收到,都会将本地文件发送后删除,tcp协议再没有收到对方的确认后,会再次隔一段时间再次发送数据
# 途中标识了返回确认信息处应该没有时间间隔
# udp协议特点,无连接,速度快,可能丢消息,传递数据有长度限制 ,跟传递设备有关,
应用场景 tcp 文件的上传和下载 如缓存视频是属于tcp,而在线看视频是属于udp
udp 主要应用于及时通讯类的
# io操作,(input output)操作,输入和输入是相对内存来说的,write send----output  read  recv----input

socket

# socket.AF_INET IPv4(默认)
# socket.AF_INET6 IPv6
# socket.AF_UNIX 只能够用于单一的Unix系统进程间通信

参数二:类型
# socket.SOCK_STREAM  流式socket , for TCP (默认)
# socket.SOCK_DGRAM   数据报式socket , for UDP
socket.SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
socket.SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET 可靠的连续数据包服务
参数三:协议
# 0(默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议

"""
服务端应该满足的特性:
    1、一直对外提供服务
    2、并发地提供服务
"""
import socket
# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # AF_INET基于网络类型   SOCK_STREAM=》TCP协议
# 2、插手机卡
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #它在bind前加 ,断开时操作系统还没回收端口号的时候加这句
phone.bind(("127.0.0.1", 8080))  # 本地回环
# 3、开机
print('111111')
phone.listen(5)
print('starting %s:%s' %("127.0.0.1", 8080))
# 4、等电话链接=>链接循环
while True:
    conn, client_addr = phone.accept()
    print(client_addr)
    # 5、收/发消息=>通信循环
    while True:
        try:
            data = conn.recv(1024)  # 最大接收的字节个数
            if len(data) == 0:  # 针对linux系统,因客户端意外断开连接的时候linux的接受的数据全部都是0
                break
            print("收到的客户端数据:", data.decode('utf-8'))
            conn.send(data.upper())
        except Exception:  # 针对windows系统,因客户端意外断开连接的时候window会报错
            break
    # 6、关闭
    conn.close()  # 挂电话
phone.close()  # 关机

# # 客户端
import socket
# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议
# 2、拨电话
phone.connect(("127.0.0.1", 8080))
# 3、发/收消息=>通信循环
while True:
    msg = input(">>: ").strip()
    phone.send(msg.encode('utf-8'))
    data = phone.recv(1024)
    print("服务的返回的数据:", data.decode('utf-8'))
# 4、关闭
phone.close()

粘包问题

# 粘包问题只会出现在tcp协议中,而不会出现在udp协议中,其中粘包问题主要是因为接受方不知到消息的界限,不知道一次性提取多少字节造成的,主要原因是由于tcp协议本省造成的,tcp为了提高效率,发送方往往要收集到足够多的数据后才会发送一个tcp,如果每次发送的数据很少,而且时间间隔很短,tcp会根据自身的优化算法将其合成一个tcp片段发送,这样接收方就收到了粘包数据
# 两种情况下的粘包问题 1. 发送端需要等到缓冲区满才能发送出去,数据时间间隔短,数据时间小,会和到一起,产生粘包;2. 接收方不及时接收缓冲区的包,造成多个包接收,可u后端发送了一段数据,服务端只收了一小部分,服务端下次在接受的时候还是从缓冲区拿上次遗留的数据,产生粘包
# 解决粘包问题,为字节流加上固定长度的报头,包头宝航字节流长度,然后一次发送到对方,对方在接受时,先从缓存中读取定长的报头,然后再取真实数据,此中,需要用到struct模块
对于服务端和客户端来说,在接收消息的时候都会经过从缓存区拿去数据问题,需要注意的是无论接受数据的多少,tcp都会将消息的数据排列完整后才会呈现在内核缓存区,
image-20200816114610369
# 远程连接  服务端
import socket
import subprocess
# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议
# 2、插手机卡
phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # 就是它,在bind前加
phone.bind(("127.0.0.1", 8080))  # 本地回环
# 3、开机
phone.listen(5)
print('starting %s:%s' % ("127.0.0.1", 8080))
# 4、等电话链接=>链接循环
while True:
    conn, client_addr = phone.accept()
    print(client_addr)
    # 5、收/发消息=>通信循环
    while True:
        try:
            cmd = conn.recv(1024)  # 最大接收的字节个数
            if len(cmd) == 0:  # 针对linux系统
                break
            obj = subprocess.Popen(cmd.decode('utf-8'),
                                   shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            res=obj.stdout.read()+obj.stderr.read()  # ???
            print(res)
            conn.send(res)
        except Exception:  # 针对windows系统
            break
    # 6、关闭
    conn.close()  # 挂电话
phone.close()  # 关机

# 客户端
import socket
# 1、买手机
phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # SOCK_STREAM=》TCP协议
# 2、拨电话
phone.connect(("127.0.0.1", 8080))
# 3、发/收消息=>通信循环
while True:
    cmd = input("[root@localhost]# ").strip()
    phone.send(cmd.encode('utf-8'))
    data = phone.recv(1024)
    print(data.decode('gbk'))
# 4、关闭
phone.close()
原文地址:https://www.cnblogs.com/feiguoguobokeyuan/p/13560556.html