Day052: socket 模块:网络编程基础

目录

一、网络编程基础概念

1. OSI 七层模型

2. TCP/IP 协议族

3. IP 地址与端口号

二、socket 模块简介

三、创建套接字

四、绑定地址和端口

五、监听连接

六、接受连接

七、发送和接收数据

1. TCP 套接字

2. UDP 套接字

八、关闭套接字

九、实际案例:基于 socket 模块的简单聊天程序

1. 服务器端代码

2. 客户端代码

十、总结


在当今互联网时代,网络编程无疑是编程领域中一个至关重要且充满魅力的分支。无论是我们日常使用的网页浏览器、在线聊天工具,还是各种网络服务后台,其底层都离不开网络编程的支持。而在 Python 世界里,socket 模块就是进行网络编程的强大基石,它为我们提供了丰富的接口,让我们能够轻松地创建客户端和服务器,实现网络间的数据通信。本文将带领大家走进 socket 模块的世界,揭开网络编程的神秘面纱。

一、网络编程基础概念

在深入了解 socket 模块之前,我们先来回顾一些网络编程的基础概念,这有助于我们更好地理解后续的内容。

1. OSI 七层模型

OSI(Open Systems Interconnection)七层模型是网络通信的一个理论框架,它将网络通信分为七层,从下到上依次是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。每一层都有其特定的功能和职责,下层为上层提供服务,上层使用下层提供的服务来完成更复杂的通信任务。虽然在实际应用中,TCP/IP 四层模型更为常用,但 OSI 七层模型对于理解网络通信的原理仍然具有重要的指导意义。

2. TCP/IP 协议族

TCP/IP 协议族是互联网的核心协议集,它包含了多种网络协议,如 TCP(Transmission Control Protocol,传输控制协议)、IP(Internet Protocol,网际协议)、UDP(User Datagram Protocol,用户数据报协议)等。TCP 提供可靠的、面向连接的传输服务,确保数据能够准确无误地从发送方传输到接收方;IP 负责数据包的寻址和路由,使数据能够在网络中正确地传输;UDP 则是一种无连接的传输协议,它不保证数据传输的可靠性,但具有传输速度快、开销小的特点,适用于对实时性要求较高的应用场景。

3. IP 地址与端口号

IP 地址是网络中用于标识设备的唯一地址,它使得数据能够准确地发送到目标设备。常见的 IP 地址有 IPv4 和 IPv6 两种版本,IPv4 地址由 32 位二进制数组成,通常用点分十进制表示,如 192.168.1.1;IPv6 地址由 128 位二进制数组成,用冒号分隔的十六进制表示,如 2001:0db8:85a3:0000:0000:8a2e:0370:7334

端口号是计算机中用于区分不同应用程序或服务的标识,它是一个 16 位的整数,取值范围是 0 ~ 65535。常见的端口号有 80(HTTP 服务)、443(HTTPS 服务)、21(FTP 服务)等。在网络通信中,IP 地址和端口号共同确定了一个网络套接字(Socket),通过它可以实现数据的发送和接收。

二、socket 模块简介

Python 的 socket 模块是基于 BSD 套接字接口实现的,它提供了对底层网络协议的封装,使得我们能够在 Python 程序中方便地进行网络编程。socket 模块的主要功能包括创建套接字、绑定地址和端口、监听连接、接受连接、发送和接收数据等。

三、创建套接字

在使用 socket 模块进行网络编程时,首先需要创建一个套接字对象。套接字的创建可以通过 socket.socket() 函数来实现,其语法如下:

socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
  • family:指定套接字的地址族,常用的有 AF_INET(IPv4)和 AF_INET6(IPv6)。

  • type:指定套接字的类型,常用的有 SOCK_STREAM(面向连接的 TCP 套接字)和 SOCK_DGRAM(无连接的 UDP 套接字)。

  • proto:指定协议,通常使用默认值 0。

  • fileno:指定一个文件描述符,用于创建套接字,通常使用默认值 None。

下面是一个创建 TCP 套接字的示例:

import socket

tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

创建 UDP 套接字的示例:

import socket

udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

四、绑定地址和端口

创建套接字后,如果我们要作为服务器端,需要将套接字绑定到一个特定的地址和端口上,以便客户端能够通过该地址和端口与服务器进行通信。绑定地址和端口可以通过 socket.bind() 方法来实现,其语法如下:

socket.bind(address)
  • address:一个元组,包含地址和端口,格式为 (host, port),其中 host 可以是 IP 地址或者主机名,port 是端口号。

示例:

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("127.0.0.1", 8080))  # 绑定到本地的 8080 端口

五、监听连接

作为服务器端,在绑定地址和端口后,需要调用 socket.listen() 方法来开始监听客户端的连接请求。该方法的语法如下:

socket.listen backlog
  • backlog:指定连接队列的最大长度,当服务器繁忙时,未被接受的客户端连接请求将被放入队列中等待处理。

示例:

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("127.0.0.1", 8080))
server_socket.listen(5)  # 设置连接队列长度为 5
print("服务器正在监听,等待客户端连接...")

六、接受连接

当服务器监听到客户端的连接请求后,可以使用 socket.accept() 方法来接受连接。该方法会返回一个元组,包含一个新的套接字对象和客户端的地址信息。新的套接字对象用于与客户端进行通信,客户端的地址信息是一个元组,包含客户端的 IP 地址和端口号。语法如下:

socket.accept()

示例:

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("127.0.0.1", 8080))
server_socket.listen(5)

client_socket, client_address = server_socket.accept()
print("客户端已连接:", client_address)

七、发送和接收数据

1. TCP 套接字

对于 TCP 套接字,数据的发送和接收分别使用 socket.sendall()socket.recv() 方法。

  • socket.sendall(data):发送数据,data 是一个字节串,该方法会将数据全部发送出去,不会因为数据量过大而阻塞。

  • socket.recv(bufsize):接收数据,bufsize 指定接收数据的缓冲区大小,返回值是一个字节串。

示例(服务器端):

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("127.0.0.1", 8080))
server_socket.listen(5)

client_socket, client_address = server_socket.accept()

# 接收客户端发送的数据
data = client_socket.recv(1024)
print("收到客户端发送的数据:", data.decode("utf-8"))

# 向客户端发送数据
client_socket.sendall("服务器已收到你的消息".encode("utf-8"))

client_socket.close()
server_socket.close()

示例(客户端):

import socket

client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(("127.0.0.1", 8080))

# 向服务器发送数据
client_socket.sendall("你好,服务器".encode("utf-8"))

# 接收服务器发送的数据
data = client_socket.recv(1024)
print("收到服务器发送的数据:", data.decode("utf-8"))

client_socket.close()

2. UDP 套接字

对于 UDP 套接字,数据的发送和接收分别使用 socket.sendto()socket.recvfrom() 方法。

  • socket.sendto(data, address):发送数据,data 是一个字节串,address 是一个元组,包含目标地址和端口。

  • socket.recvfrom(bufsize):接收数据,返回值是一个元组,包含接收到的数据和发送方的地址信息。

示例(服务器端):

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.bind(("127.0.0.1", 8080))

# 接收客户端发送的数据
data, client_address = server_socket.recvfrom(1024)
print("收到客户端发送的数据:", data.decode("utf-8"))

# 向客户端发送数据
server_socket.sendto("服务器已收到你的消息".encode("utf-8"), client_address)

server_socket.close()

示例(客户端):

import socket

client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 向服务器发送数据
client_socket.sendto("你好,服务器".encode("utf-8"), ("127.0.0.1", 8080))

# 接收服务器发送的数据
data, server_address = client_socket.recvfrom(1024)
print("收到服务器发送的数据:", data.decode("utf-8"))

client_socket.close()

八、关闭套接字

在网络通信结束后,我们需要及时关闭套接字,以释放系统资源。关闭套接字可以通过 socket.close() 方法来实现。

示例:

client_socket.close()
server_socket.close()

九、实际案例:基于 socket 模块的简单聊天程序

为了让大家更好地理解 socket 模块的实际应用,下面我们来实现一个简单的基于 TCP 协议的聊天程序,包括服务器端和客户端。

1. 服务器端代码

import socket
import threading

def handle_client(client_socket):
    while True:
        try:
            data = client_socket.recv(1024)
            if not data:
                break
            print("收到客户端消息:", data.decode("utf-8"))
            client_socket.sendall("服务器已收到你的消息".encode("utf-8"))
        except Exception as e:
            print("发生异常:", e)
            break

    client_socket.close()

def main():
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.bind(("0.0.0.0", 8080))
    server_socket.listen(5)
    print("服务器已启动,正在监听端口 8080...")

    while True:
        client_socket, client_address = server_socket.accept()
        print("客户端已连接:", client_address)
        client_thread = threading.Thread(target=handle_client, args=(client_socket,))
        client_thread.start()

if __name__ == "__main__":
    main()

2. 客户端代码

import socket

def main():
    client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client_socket.connect(("127.0.0.1", 8080))

    while True:
        message = input("请输入消息(输入 'exit' 退出):")
        if message.lower() == "exit":
            break
        client_socket.sendall(message.encode("utf-8"))

        data = client_socket.recv(1024)
        print("收到服务器消息:", data.decode("utf-8"))

    client_socket.close()

if __name__ == "__main__":
    main()

运行服务器端程序后,再运行多个客户端程序,就可以实现简单的聊天功能。客户端输入消息后,服务器会收到并回复消息,其他客户端也可以看到服务器转发的消息。

十、总结

通过本文的学习,我们了解了网络编程的基础概念,掌握了 Python socket 模块的基本用法,包括创建套接字、绑定地址和端口、监听连接、接受连接、发送和接收数据以及关闭套接字等操作,并通过一个实际案例实现了简单的聊天程序。socket 模块为我们打开了网络编程的大门,让我们能够在 Python 中轻松地创建各种网络应用程序。在后续的学习中,我们可以进一步探索基于 socket 模块的更高级的网络编程技巧,如多线程、异步 IO 等,以满足更复杂的网络应用场景的需求。

100天精通Python编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西攻城狮北

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值