python监听网页_python tcp不用循环监听


1. IP 地址

概念: 标识网络中设备的地址(需要联网才有没有联网, 是没有这个地址)

表现形式:

  • ipv4 目前主要使用的, 点分十进制的格式,(192.168.3.43)
  • 分为 4 段, 每段的范围是 0-255, 0.0.0.0 ~ 255.255.255.255
  • 公网 IP, 可以直接被别人使用访问的 ip(需要购买)
  • 局域网 ip(内网), 通过路由器或者交换机得到的 ip 都是局域网 ip, 只有处于同一个局域网的才能使用这个 ip, 电脑中查看到的 ip 都是局域网 ip.
  • ipv6 冒号 16 进程的格式

作用: IP地址可以标识网络中唯一的一台设备

查看 IP 地址

  • Linux 和 Mac : ifconfig
  • Windows : ipconfig

查看网络是否正常ping

  • ping 公网 ip 是否可以联外网, ping www.baidu.con
  • ping 局域网的 ip 检查是否在同一个局域网,设备是否连通

域名: 是 ip 地址的别名, 方便记忆, (DNS 服务器, 将域名转换为 ip 地址)

  • 127.0.0.1 本机的 ip 地址, 对应的域名 localhost

2. 端口

端口: 数据传输的通道

端口号: 是端口的唯一标识, 是一个整型数字(int)

端口的分类0-65535 一共 65536个

  • 知名端口 0-1023
  • http 协议 80
  • https : 443
  • ssh 22
  • 动态端口 1024-65535

通过 ip 找到某台主机, 设备
通过端口号,能对应主机中的一个应用程序
IP + 端口: 标识网络中唯一的一个应用程序

3. TCP

概念: 传输控制协议(主机间通信传输数据的规则)

特点:

  • 面向连接的(通信之前, 必须先建立连接)
  • 数据是可靠的
  • 发送应答
  • 超时重传
  • 错误校验
  • 流量控制

通信步骤:

  • 建立连接
  • 传输数据(通信)
  • 关闭连接

传输协议: TCP UDP

4. scoket

  • socket, 套接字, 进程间网络通信的工具.
  • 使用场景: 所有的网络通信的底层都会使用 socket

5. TCP 客户端


# 1. 创建 socket 对象       socket.socket()
# 2. 和服务器建立连接         socket对象.connect()
# 3. 发送数据给服务器         socket对象.send()
# 4. 客户端接收服务器发送的信息 socket对象.recv()
# 5. 关闭连接                socket对象.close()
# (3. 4 可以重复进行)


python 中的字符串


str: 使用引号引起来的就是字符串
bytes: 二进制类型的数据
str  --> bytes str.encode(编码类型)
bytes--> str   bytes.decode(编码类型)


程序代码:


import socket
# 1. 创建 socket 对象
# socket.AF_INET 表示 ipv4 AF_INET6 表示 ipv6
# socket.SOCK_STREAM 表示 tcp协议
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 和服务器建立连接(参数是元组)
client_socket.connect(('192.168.1.5', 8080))
print('和服务器建立连接成功')
# 3. 发送数据给服务器
# 3.1 准备数据(bytes)
send_info = '你好服务器'.encode()
# 3.2 发送数据
client_socket.send(send_info)
# 4. 客户端接收服务器发送的信息,参数表示一次接收多少字节
buf = client_socket.recv(4096)
try:
    print(f'接收到: {buf.decode()}')
except UnicodeError:
    print(f'接收到: {buf.decode("gbk")}')
# 5. 关闭连接
client_socket.close()


程序输出:


和服务器建立连接成功
接收到: 你好


注意点:
- 必须先启动服务器
- connect 是元组类型, 服务器的 ip 和端口不要写错

6. TCP 服务端


# 1. 创建 socket 对象
# 2. 绑定 IP 和端口
# 3. 设置监听, 将主动套接字变为被动套接字
# 4. 等待客户端链接阻塞等待
# 5. 接收客户端的信息
# 6. 给客户端发送信息
# 7. 关闭套接字


程序代码:


import socket
# 1. 创建 socket 对象
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 绑定 IP 和端口(参数是元组)
server_socket.bind(('', 9999)) # IP 地址为空表示绑定的是王机中任意一个ip
# 3. 设置监听, 将主动套接字变为被动套接字,参数表示最多允许多少客户端同时请求服务器(不包括已经连接成功的)
server_socket.listen(128)
# 4. 等待客户端链接阻塞等待
print('等待客户端连接')
# 返回值是元组类型(用于通信socket,客户端的 IP 和端口
new_socket, ip_port = server_socket.accept()
print(f'客户端 {ip_port} 上线')
# 5. 接收客户端的信息
buf = new_socket.recv(4096)
print(f'接收到: {buf.decode()}')
# 6. 给客户端发送信息
new_socket.send('信息收到'.encode())
# 7. 关闭套接字
new_socket.close()
server_socket.close()


程序输出:


等待客户端连接
客户端 ('192.168.1.5', 65439) 上线
接收到: 你好服务器


设置端口复用:


# 参数1 level,设置哪个级别的socket, socket.SOL_SOCKET当前的socket(固定写法)
# 参数2 option, 设置什么内容, socket.SO_REUSEADDR 端口复用
# 参数3 将内容设置为什么值, True
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)


判断客户端断开连接:


# buf: 字符串(容器)都可以直接作为 bool 类型进行判断,当容器中元素的个数为 0, 是 False, 其余是 True
if len(buf) == 0:
    pass
if buf:  # if not buf:
    pass


7. 多任务 TCP 服务端

程序代码:


import socket
import threading

def handle_client_request(new_socket, ip_port):
    while True:
        buf = new_socket.recv(4096)
        if buf:
            try:
                print(f'接收到: {buf.decode()}')
                new_socket.send('信息收到'.encode())
            except UnicodeDecodeError:
                print(f'接收到: {buf.decode("gbk")}')
                new_socket.send('信息收到'.encode("gbk"))
        else:
            print(f'{ip_port} 下线')
            break
    new_socket.close()


if __name__ == '__main__':
    # 1. 创建 socket 对象
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置端口复用
    server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 2. 绑定
    server_socket.bind(('', 9999))
    # 3. 设置监听
    server_socket.listen(128)
    # 4. 循环等待客户端链接阻塞等待
    print('等待客户端连接')
    while True:

        # 返回值是元组类型,(用于通信socket,客户端的Lio和端口port】,拆包
        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()


注意:
- 线程要启动 start()
- new_socket.close() 位置要正确