Loading

socket编程

【一】什么是socket

  • 传输层以下的操作都很复杂且固定,大神对传输层及以下层的操作进行的一个封装,至于传输层怎么封装,网络层怎么封装,数据链路层怎么封装,物理层怎么发出去,大神都将他们封装到socket模块里面了

  • socket翻译过来是套接字,套接字就是我们用来通过网络发数据和收数据的

【1】DHCP

  • DHCP就是一个自动分配、管理和回收网络地址的系统,它让设备能夠轻松地连接到网络,而不需要手动设置IP地址。
  • 想象你刚搬到一个新公寓楼里,而且你需要一个邮箱。在这个情况下,公寓的管理人(在网络中相当于DHCP服务器)会给你一个邮箱(这就像网络中的IP地址)。这个邮箱是你在这栋楼里独有的,别人不能使用同一个邮箱。如果你搬走了,管理人可以把这个邮箱分配给新来的居民。
  • 同样地,在网络中,当一台设备(比如你的电脑或智能手机)连接到网络时,DHCP服务器会给它分配一个IP地址。这个IP地址在网络中唯一地标识你的设备,使得设备能够发送和接收信息。当设备不再使用这个网络时,比如你关掉了电脑或离开了Wi-Fi范围,这个IP地址会被回收,并可以分配给其他设备使用。

【2】ARP协议

  • 简单来说,ARP是一个帮助设备在局域网内找到对方物理地址(MAC地址)的协议,就像你在办公室寻找同事一样。
  • 想象你在一个大型办公室工作,你需要给位于同一层楼的同事递送一份文件。你知道你的同事的名字(比如“Bob”),但你不知道他的办公桌在哪里。所以,你大声地问:“谁是Bob?”在听到你的呼唤后,Bob回应说:“我在这里!”并指向他的办公桌。现在你知道了Bob的具体位置,就可以直接走过去交给他文件。
  • 当你的设备(比如电脑)需要与同一局域网(LAN)中的另一台设备通信时,它知道目标设备的IP地址(这就像知道同事的名字),但它不知道目标设备的物理地址(在网络中称为MAC地址)。
  • 你的设备通过网络发送一个ARP请求,大致相当于问:“IP地址为XXX的设备的MAC地址是什么?”这就像在办公室中大声问“谁是Bob?”一样。
  • 拥有该IP地址的设备收到ARP请求后,回应其MAC地址,就像Bob回应“我在这里”一样。
  • 一旦你的设备收到了这个回应,它就会知道如何在局域网中直接寻址到目标设备,并开始通信。

【3】DNS协议

  • 简单来说,DNS就像一个互联网上的信息中心,帮助将你熟悉的网站名字(域名)转换成电脑能够理解和定位的数字地址(IP地址)。

  • 想象你想去一家餐厅吃饭,但你只知道餐厅的名字,比如“美味餐厅”,而不知道它的具体地址。为了找到餐厅的位置,你打电话给一位信息中心的工作人员(相当于DNS服务器),告诉他们你想去的餐厅名字。工作人员查找他们的信息记录(域名对应的IP地址),告诉你餐厅的确切地址。现在你知道了怎么去那家餐厅。

  • 当你想访问一个网站时,你通常会输入网站的域名,比如 www.example.com。这就像你知道餐厅的名字一样。

  • 你的电脑(或其他设备)并不知道这个域名对应的IP地址(网站的实际“网络地址”),所以它会向DNS服务器发送一个请求,询问这个域名对应的IP地址是什么。

  • DNS服务器查找它的记录,找到域名对应的IP地址,然后把这个信息返回给你的电脑。

  • 一旦你的电脑得到了这个IP地址,它就能够连接到目标网站的服务器,并加载网站内容。

【4】URL

  • 通过这个URL,你的浏览器知道如何找到并展示你请求的网页或资源,就像你通过购物中心地图找到想去的店铺一样。
  • 想象你有一张详细的购物中心地图。这张地图上标有每个商店的名称、楼层、和具体位置。当你想去特定的商店时,你会参考这张地图,找到商店的确切位置。
  • URL就像是网络世界中的这张购物中心地图。它是一种定位互联网上资源(比如网站、图片、视频等)的方法。一个URL可以告诉你资源在哪里(服务器的地址),以及如何去那里(使用的协议)。
  1. 协议 (http):告诉你使用什么方式去访问资源,就像地图上的“你在这里”标记。
  2. 主机名 (www.example.com):告诉你资源位于哪个服务器上,就像是购物中心地图上的商店名称。
  3. 端口 (80)(可选):提供访问资源需要连接的特定“门”或“入口”,就像是商店的门号。
  4. 路径 (/path/to/myfile.html):指向服务器上的具体资源,就像是指向商店内特定商品的路径。
  5. 查询字符串 (?key1=value1&key2=value2)(可选):提供额外参数,就像是你对商店员工说的“我想看这个品牌的那种款式”。
  6. 片段 (#SomewhereInTheDocument)(可选):在资源内部指向更具体的位置,就像是在商店内指向特定的一排货架。

【二】socket TCP协议

【1.0】基础版

  • 服务端
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 3.绑定地址
sk.bind(('127.0.0.1', 8080))  # ip 加 端口号 用元组包起来

# 4.创建监听
sk.listen(5)

# 5.获取连接信息
obj, addr = sk.accept()
print(obj) # <socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
print(addr) # ('127.0.0.1', 51460)

# 6.接收消息
data = obj.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
data = data.decode('utf-8')  # 将接收到的消息解码
print(f'客户端:>>>>{data}')  # 输出客户端发送的消息

# 7.发送消息
data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
obj.send(data)

obj.close()  # 关闭与对方的连接

sk.close()  # 关闭服务端

"""
<socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
('127.0.0.1', 51460)
客户端:>>>>111
请输入发送的消息:>>>>2222
"""
  • 客户端
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 3.建立连接 (三次握手)
sk.connect(('127.0.0.1', 8080))

# 4.发送消息
to_data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
sk.send(to_data)

# 5.接收消息
data = sk.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
data = data.decode('utf-8')  # 将接收到的消息解码
print(f'客户端:>>>>{data}')  # 输出客户端发送的消息

# 6.关闭连接(四次挥手)
sk.close()

"""
请输入发送的消息:>>>>111
客户端:>>>>2222
"""

【2.0】通讯循环

  • 服务端
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 3.绑定地址
sk.bind(('127.0.0.1', 8080))  # ip 加 端口号 用元组包起来

# 4.创建监听
sk.listen(5)

# 5.获取连接信息
obj, addr = sk.accept()
print(obj) # <socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
print(addr) # ('127.0.0.1', 51460)

while True:
    # 6.接收消息
    data = obj.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
    data = data.decode('utf-8')  # 将接收到的消息解码
    print(f'客户端:>>>>{data}')  # 输出客户端发送的消息

    # 7.发送消息
    data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
    obj.send(data)

obj.close()  # 关闭与对方的连接

sk.close()  # 关闭服务端

  • 客户端
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 3.建立连接 (三次握手)
sk.connect(('127.0.0.1', 8080))

while True:
    # 4.发送消息
    to_data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
    sk.send(to_data)

    # 5.接收消息
    data = sk.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
    data = data.decode('utf-8')  # 将接收到的消息解码
    print(f'客户端:>>>>{data}')  # 输出客户端发送的消息

# 6.关闭连接(四次挥手)
sk.close()

【3.0】结束通讯

  • 服务端
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 3.绑定地址
sk.bind(('127.0.0.1', 8081))  # ip 加 端口号 用元组包起来

# 4.创建监听
sk.listen(5)

# 5.获取连接信息
obj, addr = sk.accept()
print(obj) # <socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
print(addr) # ('127.0.0.1', 51460)

while True:
    # 6.接收消息
    data = obj.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
    data = data.decode('utf-8')  # 将接收到的消息解码
    print(f'客户端:>>>>{data}')  # 输出客户端发送的消息
    if data == 'q':
        break

    # 7.发送消息
    to_data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
    obj.send(to_data)

obj.close()  # 关闭与对方的连接

sk.close()  # 关闭服务端

"""
<socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
('127.0.0.1', 51460)
客户端:>>>>111
请输入发送的消息:>>>>2222
"""
  • 客户端
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 3.建立连接 (三次握手)
sk.connect(('127.0.0.1', 8081))

while True:
    # 4.发送消息
    to_data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
    sk.send(to_data)
    if to_data.decode('utf8') == 'q':
        break
    # 5.接收消息
    data = sk.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
    data = data.decode('utf-8')  # 将接收到的消息解码
    print(f'客户端:>>>>{data}')  # 输出客户端发送的消息

# 6.关闭连接(四次挥手)
sk.close()

"""
请输入发送的消息:>>>>111
客户端:>>>>2222
"""
  • 当客户端输入q之后就会断开与服务端的连接,退出循环

【4.0】空消息问题

  • 服务端不变
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 3.绑定地址
sk.bind(('127.0.0.1', 8081))  # ip 加 端口号 用元组包起来

# 4.创建监听
sk.listen(5)

# 5.获取连接信息
obj, addr = sk.accept()
print(obj) # <socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
print(addr) # ('127.0.0.1', 51460)

while True:
    # 6.接收消息
    data = obj.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
    data = data.decode('utf-8')  # 将接收到的消息解码
    print(f'客户端:>>>>{data}')  # 输出客户端发送的消息
    if data == 'q':
        break

    # 7.发送消息
    to_data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
    obj.send(to_data)

obj.close()  # 关闭与对方的连接

sk.close()  # 关闭服务端

"""
<socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
('127.0.0.1', 51460)
客户端:>>>>111
请输入发送的消息:>>>>2222
"""
  • 客户端
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 3.建立连接 (三次握手)
sk.connect(('127.0.0.1', 8081))

while True:
    # 4.发送消息
    to_data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
    if not to_data:
        print('不能输入空消息')
        continue
    sk.send(to_data)
    if to_data.decode('utf8') == 'q':
        break
    # 5.接收消息
    data = sk.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
    data = data.decode('utf-8')  # 将接收到的消息解码
    print(f'客户端:>>>>{data}')  # 输出客户端发送的消息

# 6.关闭连接(四次挥手)
sk.close()

"""
请输入发送的消息:>>>>111
客户端:>>>>2222
"""
  • 客户端加入空消息的判断

【5.0】连接循环

  • 服务端
# 1.导入模块
import socket

# 2.创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 3.绑定地址
sk.bind(('127.0.0.1', 8081))  # ip 加 端口号 用元组包起来

# 4.创建监听
sk.listen(5)

while True:

    # 5.获取连接信息
    obj, addr = sk.accept()
    print(obj)  # <socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
    print(addr)  # ('127.0.0.1', 51460)

    while True:
        # 6.接收消息
        data = obj.recv(1024)  # 1024是接收消息的大小,无需定义太大,因为TCP协议是流式传输,会把大目标拆分成一个个的小目标
        data = data.decode('utf-8')  # 将接收到的消息解码
        print(f'客户端:>>>>{data}')  # 输出客户端发送的消息
        if data == 'q':
            break

        # 7.发送消息
        to_data = input('请输入发送的消息:>>>>').strip().encode('utf8')  # 要将消息转码
        obj.send(to_data)

    obj.close()  # 关闭与对方的连接

sk.close()  # 关闭服务端

"""
<socket.socket fd=316, family=2, type=1, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 51460)>
('127.0.0.1', 51460)
客户端:>>>>111
请输入发送的消息:>>>>2222
"""
  • 客户端不变

【三】socket UDP协议

  • 服务端
import socket

# 创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 数据报协议 UDP协议

# 绑定端口
sk.bind(('127.0.0.1', 8080))

# 接收数据
data = sk.recvfrom(1024)
print(data)

  • 客户端
import socket

# 创建对象
sk = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

msg = input('请输入发送的消息:>>>>').strip().encode('utf8')
sk.sendto(msg, ('127.0.0.1', 8080))
sk.close()
posted @ 2024-01-15 10:18  HuangQiaoqi  阅读(2)  评论(0编辑  收藏  举报