Python-TCP服务端程序开发

2023-05-16

文章目录

  • 一. TCP服务端程序开发
  • 二. 端口复用
  • 三. 判断客户端程序是否断开
  • 四. 多任务版本

一. TCP服务端程序开发

"""
主动套接字: 可以收发信息的套接字
被动套接字: 不能收发信息

TCP服务端的流程:
    1. 创建socket对象
    2. 绑定, 固定服务器的ip和端口
    3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接,
    4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
    5. 新的socket接收信息
    6. 新的socket发送信息
    7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接
    注意: 其中 5,6 步骤是可以重复执行的
"""
import socket


if __name__ == '__main__':
    # 1. 创建socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2. 绑定, 固定服务器的ip和端口    socket对象.bind((IP地址, 元组)) 注意是元组
    # server_socket.bind(("192.168.218.1", 8355))
    server_socket.bind(("", 8355))   # 收不到的话可能是端口被占用了

    # 3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接    socket对象.listen(同时连接服务器的最大数量)    连接成功之后就不会占用连接名额
    server_socket.listen(128)
    print("服务等待连接中......")

    # 4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
    # socket对象.accept()   返回一个元组, (新的socket, (客户端的ip, 端口))  注意是两层元组
    new_socket, ip_port = server_socket.accept()   # 拆分赋值变量
    print(f"客户端{ip_port} 已经连接了......")

    # 5. 新的socket接收信息, 使用新的socket进行接收
    buf = new_socket.recv(4096)
    print("接收到的信息为", buf.decode("gbk"))

    # 6. 新的socket发送信息
    send_data = "信息已经收到......".encode("gbk")
    new_socket.send(send_data)

    # 7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接, 创建的socket也关闭
    new_socket.close()
    server_socket.close()

二. 端口复用

"""
问题: 在进行连接后立即执行, 会报错显示端口已经被使用
正常情况下, 服务器的代码是永远不会关闭的, 就不会出现整个问题
但是特殊情况下, 启动服务器后, 运行一次, 马上关闭再次运行, 就会出现整个bug, 端口必须要等待 30s - 2min后才能使用

解决方案:
1. 换个端口(显然不太现实, 因为客户端也需要不停的换端口)
2. 代码解决, 代码实现,让程序关闭之后, 可以立即使用整个端口, 即 端口复用
"""
import socket


if __name__ == '__main__':
    # 1. 创建socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 设置端口复用
    # level 设置哪个级别的 socket,   socket.SOL_SOCKET 表示当前socket
    # optname 设置什么内容(权限)    socket.SO_REUSEADDR 端口复用
    # value 设置为什么值   True
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

    # 2. 绑定, 固定服务器的ip和端口    socket对象.bind((IP地址, 元组)) 注意是元组
    # server_socket.bind(("192.168.218.1", 8355))
    server_socket.bind(("", 8355))   # 收不到的话可能是端口被占用了

    # 3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接    socket对象.listen(同时连接服务器的最大数量)    连接成功之后就不会占用连接名额
    server_socket.listen(128)
    print("服务等待连接中......")

    # 4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
    # socket对象.accept()   返回一个元组, (新的socket, (客户端的ip, 端口))  注意是两层元组
    new_socket, ip_port = server_socket.accept()   # 拆分赋值变量
    print(f"客户端{ip_port} 已经连接了......")

    # 5. 新的socket接收信息, 使用新的socket进行接收
    buf = new_socket.recv(4096)
    print("接收到的信息为", buf.decode("gbk"))

    # 6. 新的socket发送信息
    send_data = "信息已经收到......".encode("gbk")
    new_socket.send(send_data)

    # 7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接, 创建的socket也关闭
    new_socket.close()
    server_socket.close()

三. 判断客户端程序是否断开

"""
问题: 在客户端没有发送消息的情况下直接断开, 后续的代码还会继续执行

解决方案:
判断客户端程序是否已经断开
"""
import socket


if __name__ == '__main__':
    # 1. 创建socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 设置端口复用
    # level 设置哪个级别的 socket,   socket.SOL_SOCKET 表示当前socket
    # optname 设置什么内容(权限)    socket.SO_REUSEADDR 端口复用
    # value 设置为什么值   True
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

    # 2. 绑定, 固定服务器的ip和端口    socket对象.bind((IP地址, 元组)) 注意是元组
    # server_socket.bind(("192.168.218.1", 8355))
    server_socket.bind(("", 8355))   # 收不到的话可能是端口被占用了

    # 3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接    socket对象.listen(同时连接服务器的最大数量)    连接成功之后就不会占用连接名额
    server_socket.listen(128)
    print("服务等待连接中......")

    # 4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
    # socket对象.accept()   返回一个元组, (新的socket, (客户端的ip, 端口))  注意是两层元组
    new_socket, ip_port = server_socket.accept()   # 拆分赋值变量
    print(f"客户端{ip_port} 已经连接了......")

    # 5. 新的socket接收信息, 使用新的socket进行接收
    # 当对方的 socket close断开 后,自己的 socket 不再进行阻塞, recv接收的内容是空的, 长度为0
    buf = new_socket.recv(4096)
    if buf:
        print("接收到的信息为", buf.decode("gbk"))

        # 6. 新的socket发送信息
        send_data = "信息已经收到......".encode("gbk")
        new_socket.send(send_data)
    else:
        print(f"客户端{ip_port}已经断开连接......")

    # 7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接, 创建的socket也关闭
    new_socket.close()
    server_socket.close()

四. 多任务版本

"""
在客户端连接后会创建新的socket
"""
import socket
import threading


def handle_client_request(n_socket, client_ip_port):
    # 5. 新的socket接收信息, 使用新的socket进行接收
    # 当对方的 socket close断开 后,自己的 socket 不再进行阻塞, recv接收的内容是空的, 长度为0
    while True:  # 这里也需要循环
        buf = n_socket.recv(4096)
        if buf:
            print(f"接收到{client_ip_port}的信息为", buf.decode("gbk"))

            # 6. 新的socket发送信息
            send_data = "信息已经收到......".encode("gbk")
            n_socket.send(send_data)
        else:
            print(f"客户端{client_ip_port}已经断开连接......")
            break  # 关闭后跳出循环, 关闭socket
    # 7. 新的socket关闭, 表示不能通信的 监听的socket 关闭了, 不能接收新的客户端连接, 创建的socket也关闭
    n_socket.close()


if __name__ == '__main__':
    # 1. 创建socket对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 设置端口复用
    # level 设置哪个级别的 socket,   socket.SOL_SOCKET 表示当前socket
    # optname 设置什么内容(权限)    socket.SO_REUSEADDR 端口复用
    # value 设置为什么值   True
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

    # 2. 绑定, 固定服务器的ip和端口    socket对象.bind((IP地址, 元组)) 注意是元组
    # server_socket.bind(("192.168.218.1", 8355))
    server_socket.bind(("", 8355))  # 收不到的话可能是端口被占用了

    # 3. 设置监听, 将主动套接字变成被动套接字, 可以接收新的客户端连接    socket对象.listen(同时连接服务器的最大数量)    连接成功之后就不会占用连接名额
    server_socket.listen(128)
    print("服务等待连接中......")

    while True:  # 循环等待客户端的消息
        # 4. 阻塞等待客户端的连接, 有客户端连接, 会返回一个新的socket, 用来和客户端通信, 原始socket会监听新的创建的socket
        # socket对象.accept()   返回一个元组, (新的socket, (客户端的ip, 端口))  注意是两层元组
        new_socket, ip_port = server_socket.accept()  # 拆分赋值变量
        print(f"客户端{ip_port} 已经连接了......")

        # 创建线程, 执行任务
        sub_thread = threading.Thread(target=handle_client_request, args=(new_socket, ip_port))

        # 启动线程
        sub_thread.start()

    server_socket.close()  # 关闭监听的 socket 注意不要写在循环里面

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python-TCP服务端程序开发 的相关文章

随机推荐

  • windows中为cmd设置代理

    在CMD环境下设置代理可能不是很常用 xff0c 但是某些情况下还是可能会用到 xff0c 比如有些资源网站被墙了 xff0c 此时你如果想访问这些资源时 xff0c 只能通过代理来访问相应的资源 xff0c 而你需要在CMD环境下下载墙外
  • version `GLIBCXX_3.4.21' not found 解决办法

    在安装cmake3 5 1运行 bootstrap的时候出现如下提示 xff1a gmake cmake 是最新的 span class hljs header usr soft cmake 3 5 1 Bootstrap cmk cmak
  • Oracle死锁查询及处理

    一 数据库死锁的现象 程序在执行的过程中 xff0c 点击确定或保存按钮 xff0c 程序没有响应 xff0c 也没有出现报错 二 死锁的原理 当对于数据库某个表的某一列做更新或删除等操作 xff0c 执行完毕后该条语句不提 交 xff0c
  • Ubuntu 18.04添加中文输入法

    找到设置 xff1a 点击 Manager Installed Languages 出现下图提示 xff1a Keyboard input method system 里面有Ibus XIM fcitx none 三种输入架构 xff0c
  • KEIL问题【打开文件太多造成任何按钮都不可点】【Keil4 编译时出现RL-ARM is not allowed with this license 】【 局部变量仿真显示not in scope】

    SYD8801是一款低功耗高性能蓝牙低功耗SOC xff0c 集成了高性能2 4GHz射频收发机 32位ARM Cortex M0处理器 128kB Flash存储器 以及丰富的数字接口 SYD8801片上集成了Balun无需阻抗匹配网络
  • Django(2)模板、标签

    文章目录 一 使用Django模板修改页面二 Django模板标签 变量 列表 字典 过滤器1 default2 length3 filesizeformat4 date5 truncatechars6 safe if else标签 for
  • Django(3)模型

    文章目录 一 Django 模型 ORM二 数据库配置三 定义模型 xff08 创建数据表 xff09 四 数据库基本操作 插入数据 获取数据 xff08 1 xff09 查询所有的数据行 xff08 2 xff09 where条件查询 x
  • Django(4)表单

    文章目录 一 概述二 GET方法三 POST方法四 Request对象五 QueryDict对象 此文章参考菜鸟教程 xff1a Django 表单 菜鸟教程 runoob com Django版本 xff1a span class tok
  • Django(5)视图

    文章目录 一 视图概述二 请求对象HttpRequest xff08 1 xff09 GET xff08 2 xff09 POST xff08 3 xff09 body xff08 4 xff09 path xff08 5 xff09 me
  • Django(6)路由

    文章目录 一 路由概述二 正则路径中的分组 xff08 1 xff09 正则路径中的无名分组 xff08 2 xff09 正则路径中的有名分组 xff08 3 xff09 路由分发 三 反向解析 xff08 使用reverse xff09
  • Django(7)Admin管理工具

    文章目录 一 概述二 使用管理工具 xff08 1 xff09 激活管理工具 xff08 2 xff09 使用管理工具 xff08 3 xff09 复杂模型 xff08 4 xff09 自定义表单 xff08 5 xff09 内联 xff0
  • Django(8)ORM单表实例

    文章目录 一 Django ORM 单表实例创建新模型 二 数据库操作 xff08 1 xff09 添加数据 xff08 2 xff09 查找数据 filter exclude get order by reverse count firs
  • Django(9)ORM多表实例

    文章目录 一 Django ORM 多表实例创建模型插入数据 二 ORM 插入数据一对多 外键 ForeignKey多对多 xff08 Many ToManyField xff09 xff1a 在第三张表添加数据 三 关联管理器 对象调用1
  • Django(10)ORM聚合查询

    文章目录 一 聚合查询 aggregate 二 分组查询 annotate 三 F 查询四 Q 查询 此文章参考菜鸟教程 xff1a Django ORM 多表实例 xff08 聚合与分组查询 xff09 菜鸟教程 runoob com D
  • Python类的常用魔法方法

    文章目录 一 96 init 96 二 96 str 96 三 96 del 96 四 96 repr 96 五 使用案例 一 init span class token comment 在Python类中 有一类方法 这类方法以 两个下划
  • ubuntu 升级内核实战

    ubuntu 12 04内核是linux 3 2 0 24 xff0c 其实升级到最新版本3 3 4也没什么很大意义 xff0c 主要是集成了一些新的驱动和一些普通用户用不到的功能 xff0c 所以基本上本文纯属折腾 xff0c 但不要随便
  • centos7安装python3不影响python2

    文章目录 一 前言二 安装python3 一 前言 Centos7中很多软件命令依赖于系统自带的python2 比如yum 卸载python2会造成yum不可用 所以没必要卸载python2 如果要使用python3 可以通过软链接的方式安
  • Python异常的传递以及完整结构

    文章目录 异常的传递 异常的完整结构 异常的传递 span class token triple quoted string string 34 34 34 异常的传递是异常处理的底层机制 是原理层面 异常传递 当一行代码发生异常后 会向外
  • Python互斥锁小技巧

    span class token triple quoted string string 34 34 34 需求 创建两个线程 其中一个输出 1 52 另一个输出 A Z 输出格式要求 12A 13B 56C 5151Z 34 34 34
  • Python-TCP服务端程序开发

    文章目录 一 TCP服务端程序开发二 端口复用三 判断客户端程序是否断开四 多任务版本 一 TCP服务端程序开发 span class token triple quoted string string 34 34 34 主动套接字 可以收