Python-网络编程UDP

1. 网络通信概述


 

1.1 什么是网络


说明

  • 网络就是一种辅助双方或者多方能够连接在一起的工具
  • 如果没有网络可想 单机 的世界是多么的孤单

1.2 使用网络的目的


就是为了联通多方然后进行通信用的,即把数据从一方传递给另外一方。前面的学习编写的程序都是单机的,即不能和其他电脑上的程序进行通信,为了让在不同的电脑上运行的软件之间能够互相传递数据,就需要结束网络的功能。

小总结:

  • 使用网络能够把多方连接在一起,然后可以进行数据传递
  • 所谓的网络编程就是,让不同的电脑上的软件能够进行数据传递,即进程之间的通信

2. IP地址


ip地址:用来在网络中标记一台电脑,比如 192.168.1.1 ;在本地局域网上是唯一的。

 

2.1 ip地址的分类(ipv4 和 ipv6)(了解)


ipv4:所谓的 ipv4 就是下面所见到的 192.168.145.129 这类,ip 就是指那一戳数字,v 就是 versionipv4 其实就是所说的 ip 地址标记网络里面这个值的第 4 种版本。

ipv6:第 6 种版本

每一个 IP 地址包括两部分:网络地址 和 主机地址

192.168.145.129  192.168.145网络地址,后面的 129 是 主机地址

网络号是192.168.145, 129 是主机号,什么意思呢?

如果你的 IP 地址也是 192.168.145.xxx 的话,那么只要你的网络号和我的网络号相同,咱们就属于一个网。在一个网里面,后面的 xxx 是不能相同的,这就是每一个 IP 为什么不一样。

 

3. Linux 命令(ping,ifconfig)


查看或配置网卡信息:ifconfig

 

在 Linux 命令中,Ctrl + A 快速回到行首,Ctrl + E 快速回到行尾

 

Linux 关闭 / 开启 网络:

 

4. 端口


4.1 什么是端口


端口就好像是一个房子的门,是进入这个房子的必经之路...

如果一个程序需要收发网络数据,那么就要有这样的端口

Linux 系统中,端口可以有 65536(2的16次方) 个之多!

既然有那么多,操作系统为了统一管理,所以进行了编号,这就是 端口号

4.2 端口是怎样分配的


端口号不是随意使用的,而是按照一定的规定进行分配。

端口的分类标准有好几种,这里不做详细讲解,只介绍一下 知名端口动态端口

 

4.2.1 知名端口(Well Known Ports)


知名端口是众所周知的端口号,范围从 0 到 1023

80 端口分配给 HTTP 服务

21 端口分配给 FTP 服务

可以理解为,一些常用的功能使用的号码,好比 电话号码 110,10086,10010 一样

一般情况下,如果一个程序需要使用知名端口的需要有 root 权限

4.2.2 动态端口(Dynamic Ports)


动态端口的范围是从 1024 到 65536

之所以称为 动态端口,是因为它一般不固定分配某种服务,而是动态分配。

动态分配 是指当一个系统程序或应用程序需要网络通信时,它向主机申请一个端口,主机从可用的端口号中分配一个供他使用。

当这个程序关闭时,同时也就释放了所占用的端口号

 

5. socket 简介


5.1 不同电脑上的进程之间如何通信

首先要解决的问题是如何 唯一标识一个进程,否则通信无从谈起!在 1 台电脑上可以通过进程号(PID)来唯一标识一个进程,但是在网络中这是行不通的。其实 TCP / IP 协议已经帮我们解决了这个问题,网络层的 "IP 地址" 可以唯一标识网络中的主机,而传输层的 "协议 + 端口" 可以唯一标识主机中的应用进程。

这样利用 IP 地址、协议、端口 就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其他进程进行交互。

注意:

所谓 进程 指的是 运行的程序以及运行时用到的资源这个整体称之为进程

所谓 进程间通信 指的是 运行的程序之间的数据共享

5.2 什么是socket 


socket(简称 套接字)是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的,例如我们每天浏览网页、QQ聊天、收发email等等。

5.3 创建 socket


在 Python 中 使用 socket 模块的函数 socket 就可以完成:

import socket
socket.socket(AddressFamily, Type)

说明:

函数 socket.socket 创建一个 socket,该函数带有两个参数:

  • AddressFamily :可以选择 AF_INET用于Internet 进程间通信)或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用 AF_INET
  • Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)

创建一个 TCP socket(TCP 套接字)

import socket
# 创建 tcp 的套接字
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
# ...这里是使用套接字的功能(省略)...
# 不用的时候,关闭套接字
s.close()

创建一个 UDP socket(UDP 套接字)

import socket
# 创建 udp 的套接字
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# ...这里是使用套接字的功能(省略)...
# 不用的时候,关闭套接字
s.close()

说明

  • 套接字使用流程 与 文件的使用流程很类似
  1. 创建套接字
  2. 使用套接字收 / 发 数据
  3. 关闭套接字

 6. UDP 网络程序 - 发送、接收数据


6.1 UDP 网络程序 - 发送数据


创建一个基于 UDP 的 网络程序流程 很简单,具体步骤如下:

  1. 创建客户端套接字
  2. 发送 / 接收数据
  3. 关闭套接字

代码如下:

import socket
 # 1.创建一个 udp 套接字
 udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 
 # 2.准备接收方的地址
 # "192.168.145.1" 表示目的ip地址
 # 8080 表示目的端口
 dest_addr = ("192.168.145.1", 8080)
 # 注意 是元组 ip是字符串,端口是数字
 # udp_socket.sendto(发送的内容, 对方的ip以及port(是一个元组))
 
 # 3.从磁盘获取数据
 send_data = input("请输入要发送的数据:")
 
 # 4.发送数据到指定的电脑上的指定程序中
 udp_socket.sendto(send_data.encode("gbk"), dest_addr)
 
 # 5.关闭套接字
 udp_socket.close()

发送数据 - 代码实现:

import socket
def main():
    # 创建一个 udp 套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 从键盘获取数据
    send_data = input("请输入要发送的数据:")
    # 可以使用套接字收发数据
    # "192.168.145.1" 表示目的ip地址
    # 8080 表示目的端口
    udp_socket.sendto(send_data.encode("gbk"), 
    ("192.168.145.1", 8080))
    # 关闭套接字
    udp_socket.close()
if __name__ == '__main__':
    main()

代码升级:

import socket
def main():
    # 创建一个 udp 套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    while True:
        # 从键盘获取数据
        send_data = input("请输入要发送的数据:")
        # 如果输入的数据是exit,那么就退出程序
        if send_data == "exit":
            break
        # 可以使用套接字收发数据
        udp_socket.sendto(send_data.encode("gbk"),
         ("192.168.145.1", 8080))
    # 关闭套接字
    udp_socket.close()
if __name__ == '__main__':
    main()

 

接收数据 - 代码实现:

import socket
# 1.创建套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 2.绑定本地的相关信息,如果一个网络程序不变,则系统会随机分配
localaddr = ("", 7788) 
# ip地址和端口号,ip一般不用写,表示本机的任何一个ip
udp_socket.bind(localaddr)

# 3.等待接收对方发送的数据
recv_data = udp_socket.recvfrom(1024) 
# 1024 表示本次接收的最大字节数

# 4.显示接收到的数据
print(recv_data[0].decode("gbk"))

# 5.关闭套接字
udp_socket.close()
import socket
def main():
    # 1.创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2.绑定一个本地信息
    localaddr = ("", 7788)
    udp_socket.bind(localaddr)
    # 3.接收数据
    recv_data = udp_socket.recvfrom(1024)
    # 4.打印接收到的数据
    print(recv_data)
    # 5.关闭套接字
    udp_socket.close()
if __name__ == "__main__":
    main()
# 运行上述代码    

 

 

程序升级:

import socket
def main():
    # 1.创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 2.绑定一个本地信息
    localaddr = ("", 7788)
    udp_socket.bind(localaddr) 
    # 必须绑定自己电脑的 ip 以及 port,其他的不行,
    # 绑其他的 ip,截取收到别人要收到的消息?!
    while True:
        # 3.接收数据
        recv_data = udp_socket.recvfrom(1024)
        # recv_data这个变量中存储的是一个元组
        # (接收到的数据,(发送方的ip,port))
        recv_msg = recv_data[0]  # 存储接收到的数据
        send_addr = recv_data[1]  # 存储发送方的地址信息
        # 4.打印接收到的数据
        # print(recv_data)
        print("%s:%s" % (str(send_addr), recv_msg.decode("gbk")))
    # 5.关闭套接字
    udp_socket.close()
if __name__ == "__main__":
    main()

单工、半双工、全双工?

单工:百分之百的只能指向一个方向走,例如收音机,只能收。

半双工:对讲机,可以收,可以发,但是收的时候发不了,发的时候收不了。

全双工: 同一时刻既可以发也可以收。

问题:

  1. recvfrom 在没有数据到来时,会怎样?
  2. socket是 全双工?
  3. 飞秋 通信用的是 2425 端口,那么 QQ 呢?QQ 怎样通信?

应用:udp 聊天器


说明

  • 在一个电脑中编写 1 个程序,有 2 个功能
  • 1. 获取键盘数据,并将其发送给对方
  • 2. 接收数据并显示
  • 并且功能数据进行选择以上的 2 个功能调用

要求

1. 实现上述程序

参考代码

import socket
def main():
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定信息
    udp_socket.bind(("", 7788))
    # 循环来进行处理
    while True:
        # 发送
        # 获取要发送的内容
        send_data = input("请输入要发送的消息:")
        dest_ip = input("请输入对方的ip:")
        dest_port = int(input("请输入对方的port:"))
        udp_socket.sendto(send_data.encode("gbk"), 
        (dest_ip, dest_port))
        # 接收并显示
        recv_data = udp_socket.recvfrom(1024)
        print("%s:%s" % (recv_data[1]), recv_data[0].decode("gbk"))
        # print(recv_data)
if __name__ == "__main__":
    main()

代码升级 :

import socket

def send_msg(udp_socket):
    # 获取要发送的内容
    send_data = input("请输入要发送的消息:")
    dest_ip = input("请输入对方的ip:")
    dest_port = int(input("请输入对方的port:"))
    udp_socket.sendto(send_data.encode("gbk"), (dest_ip, dest_port))
def recv_msg(udp_socket):
    recv_data = udp_socket.recvfrom(1024)
    print("%s:%s" % (recv_data[1]), recv_data[0].decode("gbk"))
    # print(recv_data)
def main():
    # 创建套接字
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    # 绑定信息
    udp_socket.bind(("", 7788))
    # 循环来进行处理
    while True:
        print("----聊天器----")
        print("1:发送消息")
        print("2:接收消息")
        print("0:退出系统")
        option = input("请输入功能:")
        if option == "1":
            # 发送
            send_msg(udp_socket)
        elif option == "2":
            # 接收并显示
            recv_msg(udp_socket)
        elif option == "0":
            break
        else:
            print("输入有误,请重新输入!")
if __name__ == "__main__":
    main()

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值