网络编程(1) - 网络通信方式udp
1.1,网络通信概述
-
什么是网络
说明
- 网络是一种能辅助双方或者辅助多方能连接在一起的工具
- 如果没有网络,可想
单击
的世界是多么孤独
-
使用网络的目的
就是为了连同多方然后进行通信用的,即把数据从一方传递给另外一方,那些自己在电脑里写的程序都是单机的,不能和其他电脑上的程序进行通信,为了让在不同的电脑上运行的软件之间能互相传递数据,就需要借助网络的功能
小总结
- 使用网络能够把多方连接在一起,然后进行数据传递
- 所谓的网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信
1.2,ip地址(重要)
-
什么是地址
ip地址:192.165.32.14 目的:用来标记网络上的一台电脑,不允许重复
-
ip地址的作用
通过 ip地址 能够区分数据是给谁的
-
查看ip地址
Linux上:ifconfig,ip addr
关闭网卡 ifconfig + 网卡名 + down
开启网卡 ifconfig + 网卡名 + up
windows上:ipconfig
-
ip地址分类
ip v4,ip v6是ip的两个等级,ip v 1~3和ip v 5是实验版本。
目前还是以 ip v4 为主,如果要都换成 ip v6要全国上下的网点大规模更改,等到每个人身上都要都几百个ip的时候才会考虑 ip v6。
ip v4 xxx.xxx.xxx.xxx,xxx从0255,0和255不能使用,根据某地点的人数来划分ip地址,192.168.33.1254,这是c等,192.168.33是网络号,1254是主机号。如果一个地区超过254个人需要ip,那就是192.168是网络号1254.1~254是网络号
ip v4的等级如下
-
私有ip
在这么多网络 ip 中,国际规定有一部分ip地址是用于我们的局域网使用,也就是属于私网ip,不在公网中使用,他们的范围是:
10.0.0.0 ~ 10.255.255.255 172.16.0.0 ~ 172.255.255 192.168.0.0 ~192.168.255.255
-
注意
IP地址127.0.0.1 ~ 127.255.255.255用于回路测试
如:127.0.0.1可以代表本机ip地址,用于http://127.0.0.1就可以测试本机中配置的Web服务器
1.3,端口(重要)
1.4,端口分类
端口可以分为 知名端口 和 动态端口。
端口号:只有整数,范围是 0~65535
-
知名端口(well known ports)
知名端口就是总所周知的端口,范围是 0~1023
80 端口是分配给 http(上网) 服务 21 端口是分配给 FTP(文件下载) 服务
可以理解成 报警电话110 急救电话119 中国移动10086
-
动态端口(dynamic ports)
动态端口不固定分配某舟服务,范围是1024~65535
1.5,socket简介
-
不同电脑自检如何通信
a. 首先要解决的问题是如何唯一标识一个进程,否则通信无从谈起。
b. 在一台电脑上可以通过进程号(PID)来唯一标识一个进程,但是在网络中这行行不通。
c. 其实TCP/IP协议已经帮我们解决了这个问题,网络层的 “ip地址” 可以唯一标识网络中的主机,而传输层的 “协议+端口” 可以唯一标识主机中的应用进程。
d. 这样就可以利用
ip地址+协议+端口
就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其他进程进行交互注意:
- 所谓
进程
指的是:运行的程序以及运行时用到的资源这个整体称之为进程 - 所谓
进程之间的通信
指的是:运行的程序之间的数据共享
- 所谓
-
什么是socket
socket(简称
套接字
)是进程通信之间的一种方式,他与其他进程通信的一个主要不同是他能实现不同主机之间的进程通信,我们网络上各种各样的服务大多都是基于 Socket 来完成的,例如我们每天浏览网页,QQ聊天,收发 email等等 -
创建socket
在 python 中使用 socket 模块就能实现
import socket socket.socket(AddressFamile, Type)
说明:
函数 socket.socket 创建一个socket,该函数带有两个参数:
- AddressFamily:可以选择 AP_INET(用于internet进程)或者AF_UNIX(同一台机器进程通信),实际工作中常用 AF_INET
- Type:套接字类型,可以是 SOCKET_STREAM(字节流式套接,主要用于 TCP 协议)或者 SOCKET_DGRAM(数据报套接,主要用于 UDP 协议)
创建一个tcp socket(tcp套接字)
import socket # 创建tcp的套接字 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # ...这里是套接字的功能(省略)... # 不用的时候,关闭套接字 s.close()
创建一个udp socket(udp套接字)
import socket # 创建tcp的套接字 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # ...这里是套接字的功能(省略)... # 不用的时候,关闭套接字 s.close()
说明:
- 套接字使用流程 与 文件的使用流程很类似
- 创建套接字
- 使用套接字收/发数据
- 关闭套接字
1.6,udp网络程序-发送丶接收数据
-
udp网络程序-发送数据
创建一个基于udp的网络程序流程很简单,具体步骤如下:
- 创建客户端套接字
- 发送/接收数据
- 关闭套接字
代码如下:
# coding = 'utf-8' from socket import * # 1. 创建套接字 udp_socket = socket(AF_INET, SOCK_DGRAM) # 2. 准备接收方地址 # ’192.168.1.103‘ # 8080表示目的端口 dest_addr = ('192.168.2.33', '8080') # 4. 准备数据 udp_data = input('请输入你要发送的数据:\t') # 5. 发送数据 udp_socket.sendto(udp_data.encode('utf-8'), dest_addr) # 6. 关闭套接字 udp_socket.close()
注意:
判断一个ip是否可以通信:
-
ping 一个ip,如果出现类似下面的代码,可以通信
64 bytes from 172.22.7.226: icmp_seq=5 ttl=127 time=0.541 ms
-
sudo dhclient :如果本机没有ip,等待别人分配ip,就可以和同一个网络的ip通信
-
udp网络程序-接收数据
-
接收数据
# encoding = 'utf-8' from socket import * def main(): # 1. 创建套接字 upd_socket = socket(AF_INET, SOCK_DGRAM) # 2. 绑定一个本地的端口 upd_socket.bind(('', 8080)) # 3. 接收数据 recv_data = upd_socket.recvfrom(1024).decode('utf-8') # recv_data接收到的是一个元组 -> (接收的数据, (发送方ip, port)) # 4. 打印接收到的数据 print(recv_data[0].decode('utf-8')) # 5. 关闭套接字 upd_socket.close() if __name__ == '__main__': main()
-
1.7,udp端口绑定问题(重要)
-
动态分配端口
如果发送数据的时候,没有bind一个端口就发送数据,电脑会随机给这个程序一个端口
-
静态端口
给程序一个固定端口,每次发送数据都端口会不变[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-goeENb1J-1592060775678)(assets/1564297823367.png)]
-
socket使用端口不能重复
在udp里面,同一个时间,端口的使用不能相同,否则会冲突
1.9,全双工,半双工,单工
1.8,应用:udp聊天器
-
说明
- 在一个电脑中编写1个程序,有两个功能
-
- 获取键盘数据,并将其发送给对方
-
- 接收数据并显示
- 并且功能数据进行选择以上的2个功能调用
-
要求
实现上面的程序
-
参考代码
from socket import * def send_msg(udp_socket): """ 发送消息 :return: """ # 1. 发数据 # 获取要发送的内容 udp_data = input('请输入要发送的内容:\t') # 获取要发送的ip dest_ip = input('请输入要发送的ip:\t') # 获取要发送的port dest_port = input('请输入要发送的port:\t') # 发送数据 udp_socket.sendto(udp_data.encode('utf-8'), (dest_ip, int(dest_port))) def recv_msg(udp_socket): """接收数据""" # 2. 收数据 recv_data = udp_socket.recvfrom(1024) print('【数据来自 {}:{}】'.format(recv_data[1][0], recv_data[1][1])) print(recv_data[0].decode('utf-8')) def main(): # 1. 创建套接字 udp_socket = socket(AF_INET, SOCK_DGRAM) # 2. 绑定端口 udp_socket.bind(('', 8080)) # 3. 循环来处理事情 while 1: print('输入1,发送数据') print('输入2,接收数据') print('输入0,退出程序') op = input('请输入要实现的功能:\t') if op == '1': send_msg(udp_socket) elif op == '2': recv_msg(udp_socket) elif op == '0': break else: print('输入错误,请重新输入:\t') if __name__ == '__main__': main()
补充:接收数据时会出现漏洞,如果不接收绑定端口的数据,会被恶意数据堵塞
上一篇: 基于UDP协议的简单回射服务器的实现
下一篇: 2.19管程