OSI七层协议,软件架构,socket编程,TCP和UDP协议


OSI七层协议(规则)

# 七层划分为:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层

# 五层划分为:物理层,数据链路层,网络层,传输层,会话层,应用层

传输层:TCP协议和UDP协议  
网络层(路由器...) 
会话层(淘宝登录...) 
应用层(微信,浏览器...)

软件架构

C/S : client:客户端 			 server => 服务端
B/S : browser:浏览器		   server => 服务端

# 本质:B/S架构也是C/S架构

TCP和UDP协议(传输层)

TCP协议的特点:
	1. 数据可靠传输(TCP协议的三次握手和四次挥手(如下图))
  2. 速度相对于UDP协议较慢
UDP协议的特点:
	1. 数据不可靠
  2. 速度相对于TCP协议较快

tcp三次握手和四次挥手

客户端向服务端主动发起连接请求,服务端收到请求响应客户端并发起对客服端端连接请求,
客户端告诉服务端收到请求,此时才能百分百确认建立连接。

为什么建立连接是三次握手,关闭连接确是四次挥手

建立连接的时候,服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文
里发送给客户端。而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还
能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给
对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从
而导致多了一次。(客户端发起断开连接请求,服务端不能直接断开连接,因为可能还有数据没有完全
传输完毕,等这次数据传输完毕,服务端再发一次请求告诉服务端这次数据传输完了,客户端告诉服
务端收到请求,此时才彻底断开连接)

socket抽象层(不属于OSI七层协议)

# 本机的IP地址:127.0.0.1   (win+R ——>cmd——>回车——>ipconfig——>IRv4地址/IRv6地址)
192.168开头的是局域网的ip地址(公司网络),我们一般用的是广域网

socket抽象层:就是一个个的对外访问的接口(浅显的理解就是函数,然后调用函数)

在传输层当中传输的数据形式都是二进制

# 什么是Socket呢?
我们经常把**Socket翻译为套接字**,Socket是在应用层和传输层之间的一个抽象层(人为定义),它把  TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用

套接字工作流程

域名跟ip进行了绑定——>域名解析

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),
调用accept阻塞,等待客户端连接接收数据。在这时如果有个客户端初始化一个Socket,然后连接服
务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务
端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,**read在python中是receive**
最后关闭连接,一次交互结束

基于TCP协议的套接字(socket)编程

**************************************服务端****************************************

import socket

# 1. 实例化socket对象

# 参数不传递默认代表是TCP协议
server = socket.socket(type=socket.SOCK_STREAM)   # socket 模块名.类名

# 2. 绑定
server.bind(('127.0.0.1', 8001))    
# 8001——>端口(prot),服务器端要用 bind() 函数将套接字与特定的 IP 地址和端口绑定起来

# 3. 监听, 括号中是半连接池,(5)相当于服务端只服务5个人,第6个人来就报错
server.listen(5)

# 4. 接收客户端发来的信息
print("正在等待客户端发来的消息:")

# sock:当次链接对象,addr:客户端的地址, ip+port端口
sock, addr = server.accept()

# 5. 拿到数据, 单位最多接收1024个字节的数据,接收字节类型Byte类型(可能出现粘包现象)
data = sock.recv(1024)      
print(data)

# 6. 发送客户端的数据
sock.send(data.upper())

# 7. 断开链接
sock.close()

# 8.
server.close()

**************************************客户端****************************************** 
import socket

client = socket.socket()
client.connect(('127.0.0.1',8001))

# 向服务端发送数据
client.send(b'hello baby')     # 通过b前缀将字符串转换成 bytes

# 接收服务端发来的数据 
data = client.recv(1024)
print(data)
client.close()

# 客户端只能发送一次就断开,服务端只接受一个客户端服务完立马就断了

加上链接循环(服务端能够多次接收客户端发来的请求)

**************************************服务端****************************************

import socket

# 1. 实例化socket对象

# 参数不传递默认代表是TCP协议
server = socket.socket(type=socket.SOCK_STREAM)

# 2. 绑定
server.bind(('127.0.0.1', 8001))

# 3. 监听, 括号中是半连接池
server.listen(5)

# 4. 接收客户端发来的信息
print("正在等待客户端发来的消息:")

while True:
# sock:当次链接对象,addr:客户端的地址, ip+port
    sock, addr = server.accept()

    # 5. 拿到数据, 一次最多接收1024个字节的数
    data = sock.recv(1024)
    print(data)

    # 6. 发送客户端的数据
    sock.send(data.upper())

    # 7. 断开链接
    sock.close()

# 8.
server.close()

**************************************客户端**************************************** 

import socket

client = socket.socket()
client.connect(('127.0.0.1',8001))

# 向服务端发送数据
client.send(b'hello baby')

# 接收服务端发来的数据
data = client.recv(1024)
print(data)
client.close()

实现通信循环

**************************************服务端****************************************

import socket

# 1. 实例化socket对象

# 参数不传递默认代表是TCP协议 # SOCK_STREAM : tcp协议的服务端
server = socket.socket(type=socket.SOCK_STREAM)

# 2. 绑定
server.bind(('127.0.0.1', 8002))

# 3. 监听, 括号中是半连接池
server.listen(5)

# 4. 接收客户端发来的信息
print("正在等待客户端发来的消息:")

while True:
# **sock:当次链接对象**,addr:客户端的地址, ip+port
    sock, addr = server.accept()

    while True:
        # 5. 拿到数据, 一次最多接收1024个字节的数据
        try:
            data = sock.recv(1024)
            print(data)

            # 6. 发送客户端的数据
            sock.send(data.upper())
        except  as e:
            print(e)
            break

    # 7. 断开链接
    sock.close()

# 8.
server.close()

**************************************客户端**************************************** 

import socket

client = socket.socket()
client.connect(('127.0.0.1',8002))

while True:
# 向服务端发送数据
    input_data = input('请输入数据:').strip()

    client.send(input_data.encode('utf-8'))    # # 通过encode将字符串转换成 bytes

    # 接收服务端发来的数据
    data = client.recv(1024)
    print(data)
client.close()

基于UDP协议的套接字编程

**************************************服务端****************************************

import socket

# SOCK_DGRAM :udp协议的服务端

server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 数据报协议-》UDP
server.bind(('127.0.0.1', 8080))  #绑定

while True:
    data, client_addr = server.recvfrom(1024)    # client_addr客户端地址
    print('===>', data, client_addr)
    server.sendto(data.upper(), client_addr)

server.close()

**************************************客户端**************************************** 

import socket

client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 数据报协议-》UDP

while True:
    msg = input('>>: ').strip()  # msg=''
    client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))
    data, server_addr = client.recvfrom(1024)
    print(data)

client.close()

相关