程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

Python 网络编程的基础复习:理解Socket的作用

balukai 2025-05-21 12:10:04 文章精选 5 ℃

计算机网络的组成部分在逻辑上可以划分为这样的结构


五层网络体系

应用层:应用层是网络协议的最高层,解决的是具体应用问题

  • 上网我们使用的是HTTP协议 ,
  • 域名协议 DNS,
  • 支持电子邮件的SMTP协议
  • 文件传输协议 FTP

传输层,它负责为两台主机中的进程提供通信服务。

    • 传输控制协议 (Transmission Control Protocol,TCP):提供面向连接的、可靠的数据传输服务,数据传输的基本单位是报文段(segment);
    • 用户数据报协议 (User Datagram Protocol,UDP):提供无连接的、尽最大努力的数据传输服务,但不保证数据传输的可靠性,数据传输的基本单位是用户数据报。

网络层:网络层负责为分组网络中的不同主机提供通信服务,

并通过选择合适的路由将数据传递到目标主机。在发送数据时,网络层把运输层产生的报文段或用户数据封装成分组或 包进行传送。
在TCP/IP体系中,由于网络层使用IP协议,因此分组也叫IP数据报。

  • 负责相邻计算机之间的通信 处理来自传输层的分组发送请求,收到请求后,将分组装入IP数据报,填充报头,选择去往信宿机的路径,然后将数据报发往适当的网络接口。
  • 处理输入数据报:首先检查其合法性,然后进行寻径——假如该数据报已到达信宿机,则去掉报头,将剩下部分交给适当的传输协议TCP/UDP;假如该数据报尚未到达信宿,则转发该数据报。

网络层协议包括:

  • IP(Internet protocol)协议、
  • ICMP(Internet Control Message Protocol)控制报文协议、
  • ARP(Address resolution protocol)地址转换协议、
  • RARP(Reverse arp)反向地址转换协议。

IP是网络层的核心,通过路由选择将下一条IP封装后交给接口层。

IP数据报是无连接服务。

  • ICMP是网络层的补充,可以回送报文。用来检测网络是否通畅。
  • Ping命令就是发送ICMP的echo包,通过回送的echo relay进行网络测试。
  • ARP是正向地址解析协议,通过已知的IP,寻找对应主机的MAC地址。
  • RARP是反向地址解析协议,
  • 通过MAC地址确定IP地址。

数据链路层:

数据链路层通常简称为链路层。数据链路层在两个相邻节点传输数据时,将网络层交下来的IP数据报组装成帧,在两个相邻节点之间的链路上传送帧。

于是怎么管理这些0101信息的链接就有了链路层它的基本数据是帧Frame有点像动画 中的一帧。它包括点对点协议 以太网协议 无线局域网协议 通用异步收发器协议。协议只是一个规范,它必需落地到具体的实现上。

硬件实现 网络适配器(Network Adapter)或网卡(Network Interface Card,NIC)

软件实现:数据链路层的软件实现通常由操作系统或网络协议栈中的驱动程序来完成

通过软件硬件的协作实现 帧封装和解封装 差错检测和纠正 流量控制 多路访问控制

数据链路层设备 网桥

网桥的分类

  • 使用源路由网桥可以利用最佳路由。若在两个以太网之间使用并联的源路由网桥,则还可使通信量较平均地分配给每个网桥。
  • 采用透明网桥时,只能使用生成树,而使用生成树一般并不能保证所用的路由是最佳的,也不能在不同的链路中进行负载均衡。

局域网(以太网)交换机

物理层:

保数据可以在各种物理媒介上进行传输,为数据的传输提供可靠的环境。

计算机网络体系结构中的物理层,就是要解决在各种传输媒体上传输比特 0 和 1 的问题,进而给数据链路层提供透明传输比特流的服务

传输媒体分为两类:导引型传输媒体、非导引型传输媒体

  • 导引型传输媒体:同轴电缆、双绞线、光纤、电力线;
  • 非导引型传输媒体:无线电波、微波、红外线、可见光

网络的本质

1 最底层基础的还是物质是:

传输媒介,有形的电缆,电线,无线的波这些都是电气设备,他们只负责01这样信号的传输,

2 数据链接层基础的信息控制

3 网络层:通过网卡这个物理设备与计算机软件进行协使用IP相关的协议屏蔽物理层的细节,实现透明网络连接

4 传输层:TCP提供可行的传输控制,UDP不负责可行数据传输

5 应用层 上网购物使用HTTP,邮件SMTP,文件服务FTP,域名使用DNS

软件是如何实现网络编程的?

我们知道硬件设备都是直接通过操作系统控制的,因为要使用软件进行网络通讯其实还是要依赖于操作系统提供的一些API或者编程接口,也就是操作系统会提供一些程序供我们使用来,实现网络通讯。

这个切入点则是Socket编程,它给我们们程序员提供了相应的编程接口来实现自定义网络数据的传输。

Socket套接字有着悠久的历史。

它们的使用起源于 1971 年的 ARPANET,后来成为 1983 年发布的 Berkeley Software Distribution (BSD) 操作系统中的一个 API,称为 Berkeley 套接字。

当互联网在 1990 年代随着万维网的出现而起飞时,网络编程也随之兴起。Web 服务器和浏览器并不是唯一利用新连接的网络并使用套接字的应用程序。各种类型和规模的客户端-服务器应用程序都得到了广泛使用。

今天,尽管套接字 API 使用的底层协议多年来不断发展,并且开发了新的协议,但低级 API 保持不变。

主要套接字 API 函数和方法包括:

  • socket()
  • .bind()
  • .listen()
  • .accept()
  • .connect()
  • .connect_ex()
  • .send()
  • .recv()
  • .close()

TCP 套接字

您将使用 创建一个套接字对象,将套接字类型指定为 。执行此操作时,使用的默认协议是传输控制协议 (TCP)。这是一个很好的默认值,可能是您想要的。socket.socket()socket.SOCK_STREAM

为什么要使用TCP?传输控制协议 (TCP):

  • 可靠:发送方会检测并重新传输网络中丢弃的数据包。
  • 有顺序的数据交付:应用程序按照发送方写入数据的顺序读取数据。

相比之下,使用的用户数据报协议 (UDP) 套接字创建不可靠,接收方读取的数据可能与发送方的写入不一致。socket.SOCK_DGRAM

实际上以TCP为例子,两台机器通过 IP 地址 确认特此的位置,通过端口确定彼此数据交换的point

服务器实现常用的API操作

服务器为设置“侦听”套接字而进行的 API 调用:服务器程序在本机上监听指定的端口,如果有用户连接上来,就处理这个连接,接收处理返回数据

  • socket()
  • .bind()
  • .listen()
  • .accept()

客户端

调用以建立与服务器的连接并启动三次握手。握手步骤很重要,因为它确保连接的每一端都可以在网络中访问,换句话说,客户端可以访问服务器,反之亦然。可能只有一个主机、客户端或服务器可以访问另一个主机、客户端或服务器。

.connect()

中间是往返部分,其中使用对 和 的调用在客户端和服务器之间交换数据。

.send().
recv()
import socket
target_host = "www.baidu.com" 
target_port = 80  # create a socket object 
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
client.connect((target_host,target_port))  

客户端连接远程服务器的时候,要知道对对的IP 与端口,这样计算机操作系统对过内核与网络设备发对应 的数据通过网络硬件传输出去。


写一个简单的Echo网络应答服务,了解一下Socket

服务端

# echo-server.py

import socket

HOST = "127.0.0.1"  # Standard loopback interface address (localhost)
PORT = 65432  # Port to listen on (non-privileged ports are > 1023)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print(f"Connected by {addr}")
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)

.bind()socket.AF_INET(host, port)

host可以是主机名、

IP 地址或空字符串。如果使用 IP 地址,则应为 IPv4 格式的地址字符串。IP 地址是环回接口的标准 IPv4 地址,因此只有主机上的进程才能连接到服务器。

如果传递空字符串,服务器将接受所有可用 IPv4 接口上的连接。

port表示要接受来自客户端的连接的 TCP 端口号。它应该是从 到 的整数,因为它是保留的。如果端口号小于1024 ,则某些系统可能需要超级用户权限。因为这些小的端口号是系统保留给一些特定程序使用的。

例如上网的HTTP协议使用的是80端口

https://www.baidu.com:443

在浏览器打开这个地上也是能自动跳转到百度首页的

HTTPS默认端口是 443

接收网络链接

conn, addr = s.accept()

读取对方网络传输的数据,这时原数据是业务数据直到无数据可读取,则退出并且关闭这个链接

data = conn.recv(1024)

if not data:

break

客户端代码

# echo-client.py

import socket

HOST = "127.0.0.1"  # The server's hostname or IP address
PORT = 65432  # The port used by the server

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(b"Hello, world")
    data = s.recv(1024)

print(f"Received {data!r}")

与服务器相比,客户端非常简单。

它创建一个套接字对象,使用 .connect() 连接到服务器,并调用以发送其消息。

最后,它调用以读取服务器的回复,然后打印它。s.sendall()s.recv()

总结一下

服务器程序在本机的指定端口监牢网络链接

客户端对指定的IP的服务器的特定端口发送请求,而客户端自己会随机使用本机的一个端口与对方通讯。


回环地址

使用环回接口(IPv4 地址或 IPv6 地址)时,数据永远不会离开主机或接触外部网络。在上图中,环回接口包含在主机内部。这表示环回接口的内部性质,并显示传输该接口的连接和数据是主机本地的。这就是为什么您还会听到环回接口和 IP 地址或称为“localhost”的原因。127.0.0.1::1127.0.0.1::1

应用程序使用环回接口与主机上运行的其他进程进行通信,并与外部网络进行安全和隔离。因为它是内部的,并且只能从主机内部访问,所以它不会公开。


当您使用应用程序以外的 IP 地址或在应用程序中使用时

它可能绑定到连接到外部网络的以太网接口。


处理多连接服务器

我们知道服务器程序可以处理多个客户端连接那。

服务器程序应该怎么写


import sys
import socket
import selectors
import types

sel = selectors.DefaultSelector()

# ...

host, port = sys.argv[1], int(sys.argv[2])
lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
lsock.bind((host, port))
lsock.listen()
print(f"Listening on {(host, port)}")
lsock.setblocking(False)
sel.register(lsock, selectors.EVENT_READ, data=None)

try:
    while True:
        events = sel.select(timeout=None)
        for key, mask in events:
            if key.data is None:
                accept_wrapper(key.fileobj)
            else:
                service_connection(key, mask)
except KeyboardInterrupt:
    print("Caught keyboard interrupt, exiting")
finally:
    sel.close()
def accept_wrapper(sock):
    conn, addr = sock.accept()  # Should be ready to read
    print(f"Accepted connection from {addr}")
    conn.setblocking(False)
    data = types.SimpleNamespace(addr=addr, inb=b"", outb=b"")
    events = selectors.EVENT_READ | selectors.EVENT_WRITE
    sel.register(conn, events, data=data)
def service_connection(key, mask):
    sock = key.fileobj
    data = key.data
    if mask & selectors.EVENT_READ:
        recv_data = sock.recv(1024)  # Should be ready to read
        if recv_data:
            data.outb += recv_data
        else:
            print(f"Closing connection to {data.addr}")
            sel.unregister(sock)
            sock.close()
    if mask & selectors.EVENT_WRITE:
        if data.outb:
            print(f"Echoing {data.outb!r} to {data.addr}")
            sent = sock.send(data.outb)  # Should be ready to write
            data.outb = data.outb[sent:]

# ...

客户程序也作一下响应的调整

# multiconn-client.py

import sys
import socket
import selectors
import types

sel = selectors.DefaultSelector()
messages = [b"Message 1 from client.", b"Message 2 from client."]

def start_connections(host, port, num_conns):
    server_addr = (host, port)
    for i in range(0, num_conns):
        connid = i + 1
        print(f"Starting connection {connid} to {server_addr}")
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.setblocking(False)
        sock.connect_ex(server_addr)
        events = selectors.EVENT_READ | selectors.EVENT_WRITE
        data = types.SimpleNamespace(
            connid=connid,
            msg_total=sum(len(m) for m in messages),
            recv_total=0,
            messages=messages.copy(),
            outb=b"",
        )
        sel.register(sock, events, data=data)

# ...


实际上这段代码中的写法与JavaNOI网络编程的写法十分的类似。

以下的socket数据是没有一定规范的

如果你想自己定义一个协议规范,就形成了HTTP协议

协议标头字典中所需的标头或子标头如下所示:

名字

描述

byteorder

机器的字节顺序(使用)。您的应用程序可能不需要这样做。sys.byteorder

content-length

内容的长度(以字节为单位)。

content-type

例如,有效负载中的内容类型或
.text/jsonbinary/my-binary-type

content-encoding

内容使用的编码,例如,用于 Unicode 文本或二进制数据。utf-8binary


GET /index.html

当我们使用socket发磅这一段内容的时候,服务器就知道我们要得到index.html这个内容

浏览器实际上是通过socket发磅这个协议串,服务器会按照这个规范摸摸对应 请求找到数据返回给浏览器。

最近发表
标签列表