1-创建UDP聊天室


注:本系列的环境是VScode+WSL,使用说明可参考 官方文档wsl配置anaconda的步骤

我们在这一章的目的是建立一个UDP套接字,并尝试发送数据,首先了解一下TCP/IP协议族的基本框架:

在这里插入图片描述

IP地址和端口号

IP地址的目的是在网络层标记设备,端口号是在传输层标记应用程序/进程。

Linux中可通过ifconfig查看IP地址和端口号,Windows中通过ipconfig查看。

IP地址分为ipv4和ipv6,分别对应上面的inet和inet6。ipv4地址分为网络地址和主机地址,按照划分的位数不同可分为A~E共5类。我们也定义了一些私有IP,他们不能在公网中使用,范围为:

10.0.0.0~255.255.255

172.16.0.0~172.31.255.255

192.168.0.0~192.168.255.255

私有IP经过NAT(Network Address Translator)路由器转换为全局IP地址才能完成和外界的通信,NAT和NAPT的知识详见《图解TCP/IP》第五章第六节。

端口号

简单讲,IP标记设备,端口号标记设备上的进程。

0~1023都是特殊端口号,需要root权限才能使用,80端口分配给HTTP服务,21端口分配给FTP服务;其余端口都是动态端口,1024~65535。

socket的创建

创建第一个套接字

import socket
socket.socket(socket.AddressFamily,type)

第一个参数控制是ipv4还是ipv6,分别对应socket.AF_INETsocket.AF_INET6

第二个参数控制tcp还是udp,分别对应socket.SOCK_STREAMsocket.SOCK_DGRAM

创建并使用套接字的流程和创建并打开文件的流程很像:

import socket
# 创建udp_socket
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 使用socket

#关闭socket
s.close()

创建udp_socket,并收发数据

需求: 创建udp_socket,向(“192.168.163.24”,8800)发送"hahaha"

#!coding=utf-8
import socket

def main():
    # 1. 创建udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 2. 使用套接字收发数据
    dest_addr = ("192.168.163.24",8800)
    udp_socket.sendto(b'hahaha',dest_addr)
    # 3. 关闭套接字
    udp_socket.close()

if __name__ == "__main__":
    main()

注意两点:

  1. 发送地址为目标IP和目标端口的元组,缺一不可

  2. 发送内容必须是bytes类型,不能是string类型。

    对于string类型的数据,要么像上文这样添加b前缀,要么加上.encode('utf-8')的后缀,如果是windows,需要用gbk编码。

改进:循环发送数据

#!coding=utf-8
import socket

def main():
    # 1. 创建udp套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    while True:
        # 2. 使用套接字收发数据
        # 接收方
        dest_addr = ("192.168.163.24",8800)
        # 发送内容
        send_content = input("要发送的内容")
        # 发送数据
        udp_socket.sendto(send_content.encode('utf-8'),dest_addr)
        # 判断是否停止发送数据
        if send_content=="exit":
            break
    # 3. 关闭套接字
    udp_socket.close()

if __name__ == "__main__":
    main()

绑定端口

local_addr = ('',7788)
udp_socket.bind(local_addr)

UDP socket发送数据的完整流程

  1. 创建套接字
  2. 绑定本地端口
  3. 发送数据
  4. 关闭套接字

简易版代码:

import socket

def main():
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 绑定端口
    local_addr = ('',7788)
    udp_socket.bind(local_addr)
    while True:
        # 发送数据
        dest_addr = ('192.168.22.33',9900)
        send_content = input("要发送的内容:")
        udp_socket.sendto(send_content.encode('utf-8'),dest_addr)
        # 判断是否停止
        if send_content == "exit":
            break
    udp_socket.close()
if __name__ == "__main__":    
    main()

可以将接收信息和发送信息分别写成子函数,实现半双工的UDP聊天室(UDP支持全双工的工作方式)

import socket

def send_msg(udp_socket):
    """发送信息"""
    dest_addr = ('127.0.0.1',9900)
    send_content = input("要发送的内容:")
    udp_socket.sendto(send_content.encode('utf-8'),dest_addr)

def recv_msg(udp_socket):
    """接收信息"""
    recv_data = udp_socket.recvfrom(1024)
    recv_msg = recv_data[0].decode('utf-8')
    source = str(recv_data[1])
    return recv_msg,source


def main():
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 绑定端口
    local_addr = ('',7788)
    udp_socket.bind(local_addr)
    while True:
        # 发送数据
        send_msg(udp_socket)
        # 接收信息
        recv_content,source_ip = recv_msg(udp_socket)
        print("接收来自%s的信息:%s"%(source_ip,recv_content))
        # 判断是否停止
        if recv_content == "exit":
            break
    udp_socket.close()
    
if __name__ == "__main__":
    main()

加入功能选项:

#coding=utf-8

import socket

def send_msg(udp_socket):
    """发送消息"""
    send_data = input("输入要发送的内容")
    dest_ip = input("请输入dest_ip: ")
    dest_port = input("请输入dest_port: ")
    send_addr = (dest_ip,int(dest_port))
    udp_socket.sendto(send_data.encode('utf-8'),send_addr)

def recv_msg(udp_socket):
    recv_data = udp_socket.recvfrom(1024)
    recv_msg = recv_data[0].decode('utf-8')
    source = str(recv_data[1])
    return recv_msg,source

def main():
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    # 绑定端口号
    port_addr = ("",7999)
    udp_socket.bind(port_addr)
    while True:
        print("----xxx聊天器-------")
        print("1:发送数据\n2:接收消息\n3:退出系统")
        op = int(input("输入功能选项"))
        if op == 1:
            # 发送数据
            send_msg(udp_socket)
        elif op == 2:
            # 接收数据
            recv_msg,source_ip = recv_msg(udp_socket)
            print("接收来自%s的信息:%s" % (source_ip,recv_msg))
        elif op ==3:
            # 关闭套接字
            print("关闭套接字")
            udp_socket.close()
        else:
            print("输入有误,重新输入")

if __name__=="__main__":
    main()

猜你喜欢

转载自blog.csdn.net/weixin_43721070/article/details/121753175