Scoket层(TCP,TDP)

【一】Scoket层在哪

  • 还是用图来说话,一目了然。

img

【二】什么是socket

  • Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

    • 在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面
    • 对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
  • 所以,我们无需深入理解tcp/udp协议,socket已经为我们封装好了,我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的。

  • 也有人将socket说成ip+port

    • ip是用来标识互联网中的一台主机的位置
    • 而port是用来标识这台机器上的一个应用程序
    • ip地址是配置到网卡上的
    • 而port是应用程序开启的
    • ip与port的绑定就标识了互联网中独一无二的一个应用程序
  • 而程序的pid是同一台机器上不同进程或者线程的标识

【三】套接字发展史及分类

  • 套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。
  • 一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。
  • 这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是
    • 基于文件型的
    • 基于网络型的。

【1】基于文件类型的套接字家族

  • 套接字家族的名字:
    • AF_UNIX
  • unix一切皆文件
    • 基于文件的套接字调用的就是底层的文件系统来取数据
    • 两个套接字进程运行在同一机器
    • 可以通过访问同一个文件系统间接完成通信

【2】基于网络类型的套接字家族

  • 套接字家族的名字:
    • AF_INET
  • (还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现
    • 所有地址家族中,AF_INET是使用最广泛的一个
    • python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

【四】TCP协议

# 创建socket对象
server = socket()
# 监听端口
IP = '127.0.0.1'
PORT = 8080
server.bind((IP, PORT))
# 监听连接对象个数
server.listen(5)
# 创建连接对象
conn, addr = server.accept()
# 通过连接对象接收数据 1kb = 1024 bytes  
conn.recv(1024)  # 最大1024

【1.0】基础版

服务端

from socket import socket

server = socket()
server.bind(('127.0.0.1', 9696))
server.listen(5)
conn, addr = server.accept()
from_client_lsg = conn.recv(1024)
from_client_lsg = from_client_lsg.decode('utf8')
print(from_client_lsg)
send_to_client_msg = '我是服务端'
send_to_client_msg = send_to_client_msg.encode('utf8')
conn.send(send_to_client_msg)
conn.close()
server.close()

客户端

from socket import socket
client = socket()
client.connect(('127.0.0.1', 9696))
send_to_server_msg = '我是客户端'
send_to_server_msg = send_to_server_msg.encode('utf8')
client.send(send_to_server_msg)
from_server_msg = client.recv(1024)
from_server_msg = from_server_msg.decode('utf8')
print(from_server_msg)
client.close()

【2.0】循环版

服务端

from socket import socket

server = socket()

server.bind(('127.0.0.1', 9696))
server.listen(5)
while True:
    conn, addr = server.accept()
    msg = conn.recv(1024)
    msg = msg.decode('utf8')
    print(f'msg:>>>{msg}')
    if msg == 'q':
        conn.close()
        break
    while True:
        send_msg = input("发送的消息 :>>>> ").strip()
        if not send_msg: continue
        conn.send(send_msg.encode('utf8'))
        break
server.close()

客户端

from socket import socket

while True:
    client = socket()
    client.connect(('127.0.0.1', 9696))
    send_msg = input("请输入消息 :>>>> ").strip()
    if not send_msg: continue
    client.send(send_msg.encode('utf-8'))
    if send_msg == 'q':
        client.close()
        break

    msg = client.recv(1024)
    print(msg.decode('utf8'))

【五】UDP协议

服务端

import socket

server = socket.socket(type=socket.SOCK_DGRAM)
server.bind(('127.0.0.1', 8888))
msg, addr = server.recvfrom(1024)
print(msg.decode('utf8'))
print(addr)
data = '我是服务端'
data = data.encode('utf8')
server.sendto(data, addr)

客户端

import socket

client = socket.socket(type=socket.SOCK_DGRAM)
msg = '我是客户端'
msg = msg.encode('utf8')
client.sendto(msg, ('127.0.0.1', 8888))
msg, addr = client.recvfrom(1024)
print(msg.decode('utf8'))
print(addr)

【补充】struct模块

  • struct.pack()
    

    是Python内置模块

    struct
    

    中的一个函数

    • 它的作用是将指定的数据按照指定的格式进行打包,并将打包后的结果转换成一个字节序列(byte string)
    • 可以用于在网络上传输或者储存于文件中。
  • struct.pack(fmt, v1, v2, ...)
    
    • 其中,fmt为格式字符串,指定了需要打包的数据的格式,后面的v1,v2,...则是需要打包的数据。
    • 这些数据会按照fmt的格式被编码成二进制的字节串,并返回这个字节串。
  • fmt
    

    的常用格式符如下:

    • x --- 填充字节
    • c --- char类型,占1字节
    • b --- signed char类型,占1字节
    • B --- unsigned char类型,占1字节
    • h --- short类型,占2字节
    • H --- unsigned short类型,占2字节
    • i --- int类型,占4字节
    • I --- unsigned int类型,占4字节
    • l --- long类型,占4字节(32位机器上)或者8字节(64位机器上)
    • L --- unsigned long类型,占4字节(32位机器上)或者8字节(64位机器上)
    • q --- long long类型,占8字节
    • Q --- unsigned long long类型,占8字节
    • f --- float类型,占4字节
    • d --- double类型,占8字节
    • s --- char[]类型,占指定字节个数,需要用数字指定长度
    • p --- char[]类型,跟s一样,但通常用来表示字符串
    • ? --- bool类型,占1字节
  • 具体的格式化规则可以在Python文档中查看(链接)。

img

import json
import struct

header = {
    'file_size': 20255
}
head_bytes = bytes(json.dumps(header), encoding='utf-8')

head_len_bytes = struct.pack('i', len(head_bytes))

print(f"这是原本的数据 :>>>> {header}")
print(f"这是json序列化后的数据 :>>>> {head_bytes}")
print(f"这是压缩后的数据 :>>>> {head_len_bytes}")
posted @ 2024-01-16 16:18  蓝幻ﹺ  阅读(45)  评论(0编辑  收藏  举报