socket

TCP网络编程学习笔记(完整版)


一、网络基础概念

1. IP地址

  • 作用:在网络中唯一标识一台设备
  • 查看方式
    • Windows系统使用命令:ipconfig
    • Linux/Mac系统使用命令:ifconfig
  • 测试网络连通性:使用 ping [IP地址] 命令
  • 本机回环地址127.0.0.1,用于本地测试

💡 示例:

ping 192.168.1.1
ipconfig
ifconfig

2. 端口

  • 作用:标识一台设备上运行的某个具体程序
  • 端口号范围:共65536个(0 ~ 65535)
    • 知名端口号:0 ~ 1023(如HTTP默认80、FTP默认21)
    • 动态/私有端口号:1024 ~ 65535(用户自定义)

⚠️ 注意事项:

  • 同一个端口不能被多个程序同时占用
  • 服务器程序通常绑定知名端口或固定端口供客户端访问

二、TCP协议概述

  • TCP全称:Transmission Control Protocol
  • 特点
    • 面向连接(三次握手建立连接)
    • 可靠传输(数据无差错、有序到达)
    • 基于字节流(数据没有边界)
  • 适用场景
    • 要求数据准确性和顺序性的通信
    • 如网页请求、文件下载、邮件发送等

三、编码与解码

  • 网络传输要求:只能传输二进制数据(bytes类型)
  • 字符串转二进制:使用 .encode("utf-8")
  • 二进制转字符串:使用 .decode("utf-8")
  • 注意事项
    • 编码和解码必须使用相同字符集,否则会乱码
    • 推荐统一使用 UTF-8 编码

📌 示例:

msg = "你好,世界!"
data = msg.encode("utf-8")  # 编码为二进制
print(data)  # 输出: b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81'

decoded_msg = data.decode("utf-8")
print(decoded_msg)  # 输出: 你好,世界!

四、TCP客户端基本流程

实现步骤:

  1. 创建客户端套接字对象

    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    • socket.AF_INET: 使用IPv4协议
    • socket.SOCK_STREAM: 使用TCP协议
  2. 连接服务端

    tcp_client_socket.connect(("127.0.0.1", 8080))
    
    • 参数是元组格式 (服务器IP地址, 服务器端口号)
    • 如果服务器在本机,可使用 127.0.0.1
  3. 发送数据(需先编码)

    data = "Hello Server".encode("utf-8")
    tcp_client_socket.send(data)
    
  4. 接收数据(需解码)

    recv_data = tcp_client_socket.recv(1024)  # 每次最多接收1024字节
    print(recv_data.decode("utf-8"))
    
    • recv() 是阻塞方法,等待数据到来才继续执行
  5. 关闭客户端套接字

    tcp_client_socket.close()
    

✅ 完整示例:

import socket

# 创建客户端套接字
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 连接服务端
client_socket.connect(("127.0.0.1", 8080))

# 发送数据
send_data = "你好,服务器!".encode("utf-8")
client_socket.send(send_data)

# 接收响应
recv_data = client_socket.recv(1024)
print("收到回复:", recv_data.decode("utf-8"))

# 关闭连接
client_socket.close()

五、TCP服务端实现

1. 简单版本流程

实现步骤:

  1. 创建服务端套接字

    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
  2. 绑定IP和端口号

    tcp_server_socket.bind(("", 8080))  # "" 表示监听本机所有网卡
    
  3. 设置监听队列

    tcp_server_socket.listen(128)
    
    • 参数表示最大排队数量
  4. 等待接受客户端连接请求

    client_socket, client_ip = tcp_server_socket.accept()
    
    • 返回值是一个元组,第一个元素是新的通信socket,第二个是客户端地址信息
  5. 接收数据

    data = client_socket.recv(1024)
    print("收到消息:", data.decode())
    
  6. 发送数据

    client_socket.send(b"Hello Client")
    
  7. 关闭套接字

    client_socket.close()
    tcp_server_socket.close()
    

✅ 完整示例:

import socket

# 创建服务端套接字
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 绑定地址和端口
server_socket.bind(("", 8080))

# 设置监听
server_socket.listen(128)

# 等待客户端连接
client_socket, client_addr = server_socket.accept()

# 接收数据
recv_data = client_socket.recv(1024)
print("客户端说:", recv_data.decode())

# 发送回复
client_socket.send(b"Server received your message")

# 关闭连接
client_socket.close()
server_socket.close()

2. 复杂版本(多进程并发处理)

功能说明:

  • 支持多个客户端同时连接
  • 使用 multiprocessing 模块创建子进程处理每个客户端请求

核心代码结构:

import socket
import multiprocessing

def handler_client_request(client_socket):
    """处理客户端请求"""
    while True:
        data = client_socket.recv(1024)

        if len(data) == 0:
            print("客户端已断开连接")
            break

        print("收到消息:", data.decode("utf-8"))

        # 发送回应
        client_socket.sendall("服务端已收到消息".encode("utf-8"))

    client_socket.close()

def main():
    # 创建服务端套接字
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 设置端口复用
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

    # 绑定地址和端口
    server_socket.bind(("", 8080))

    # 设置监听
    server_socket.listen(128)

    print("服务端启动成功,等待连接...")

    while True:
        # 等待客户端连接
        client_socket, client_addr = server_socket.accept()
        print(f"新连接来自:{client_addr}")

        # 创建子进程处理该客户端
        p = multiprocessing.Process(target=handler_client_request, args=(client_socket,))
        p.start()

    # 不会执行到这,但保留关闭语句作为规范
    server_socket.close()

特点说明:

  • multiprocessing.Process:每个客户端连接分配一个独立进程处理
  • setsockopt():设置端口复用,避免服务重启时出现“Address already in use”错误
  • while True循环:持续等待客户端连接,实现多客户端支持
  • 异常处理:检测客户端是否关闭连接(收到空数据)

六、总结要点(补充细节)

内容 说明
socket模块 Python标准库中的网络通信核心模块
客户端和服务端 都需要经历创建套接字、连接、收发数据、关闭连接的基本流程
TCP通信 必须先建立连接,通信可靠、有序
数据传输 必须使用二进制格式,注意编解码一致性
多客户端处理 可以使用多线程或多进程技术实现并发处理
端口复用设置 使用 setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
异常处理 应对客户端突然断开、超时等情况
recv阻塞 默认是阻塞模式,可通过设置非阻塞进行优化

七、常见问题解答

Q1: 为什么使用 127.0.0.1

  • 这是本机回环地址,用于测试本机网络应用,不经过物理网络接口。

Q2: recv() 方法为什么会阻塞?

  • 因为它是同步阻塞IO,默认情况下会一直等待直到有数据到达或连接关闭。

Q3: 为什么要设置 SO_REUSEADDR

  • 避免服务端意外崩溃后端口处于 TIME_WAIT 状态导致无法立即重启。

Q4: 为什么最大监听数设为128?

  • 一般开发环境下足够使用。生产环境可根据需求调整,但受限于系统配置。

posted @ 2025-06-04 11:31  玉米面手雷王  阅读(24)  评论(0)    收藏  举报