Python进阶之网络编程
网络通信
使用网络的目的
把多方链接在一起,进行数据传递;
网络编程就是,让不同电脑上的软件进行数据传递,即进程间通信;
ip地址
ip地址概念和作用
IP地址是什么:比如192.168.1.1 这样的一些数字;
ip地址的作用:用来在电脑中 标识唯一一台电脑,比如192.168.1.1;在本地局域网是唯一的。
网卡信息
查看网卡信息
Linux:ifconfig
windows:ipconfig
- ensxx:用来与外部进行通信的网卡;
- lo:环回网卡,用来进行本地通信的;
linux关闭/开启网卡:sudo ifconfig ensxx down/up
ip和ip地址的分类
ip分为ipv4和ipv6
ip地址分为:
- A类地址
- B类地址
- C类地址
- D类地址--用于多播
- E类地址--保留地址,因ipv6诞生,已无用
- 私有ip
单播--一对一
多播--一对多
广播--多对多
端口
ip:标识电脑;
端口:标识电脑上的进程(正在运行的程序);
ip和端口一起使用,唯一标识主机中的应用程序,进行统一软件的通信;
端口分类
知名端口
固定分配给特定进程的端口号,其他进程一般无法使用这个端口号;
小于1024的,大部分都是知名端口;
范围从0~1023;
动态端口
不固定分配,动态分配,使用后释放的端口号;
范围1024~65535;
socket
socket的概念
socket是进程间通信的一种方式,能实现不同主机间的进程间通信,即socket是用来网络通信必备的东西;
创建socket
创建套接字:
import socket
soc = socket.socket(AddressFamily, Type)
函数socket.socket创建一个socket,该函数有两个参数:
Address Family:可选 AF_INET(用于internet进程间通信)和AF_UNIX(用于同一台机器进程间通信);
Type:套接字类型,可选 SOCK_STREAM(流式套接字,主用于TCP协议)/SOCK_DGRAM(数据报套接字,主用于UDP套接字);
创建tcp套接字
import socket
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
...
soc.close()
创建udp套接字
import socket
soc = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
...
soc.close()
udp
udp使用socket发送数据
在同一局域网内发消息;
如果用虚拟机和windows,要用桥接模式,确保在同一局域网内;
import socket
def main():
# 创建一个udp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 使用套接字收发数据
udp_socket.sendto(b"hahaha", ("193.168.77.1", 8080))
# 关闭套接字
udp_socket.close()
if __name__ == "__main__":
main()
udp发送数据的几种情况:
- 在固定数据的引号前加b,不能使用于用户自定义数据;
- 用户自定义数据,并进行发送,使用.encode("utf-8")进行encode编码
- 用户循环发送数据
- 用户循环发送数据并可以退出
只贴出最后一种情况,即完整代码
import socket
def main():
# 创建一个udp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while 1:
# 从键盘获取要发送的数据
send_data = input("请输入你要发送的数据:")
if send_data == "exit":
break
# 使用套接字收发数据
udp_socket.sendto(send_data.encode("utf-8"), ("193.168.77.1", 8080))
# 关闭套接字
udp_socket.close()
if __name__ == "__main__":
main()
udp接收数据
接收到的数据是一个元组,元组第一部分是发送方发送的内容,元组第二部分是发送方的ip地址和端口号;
import socket
def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
localaddr = ('', 8080)
udp_socket.bind(localaddr) # 必须绑定自己电脑的ip和端口
# 接收数据
recv_data = udp_socket.recvfrom(1024)
# recv_data这个变量存储的是一个元组,例如 (b'hahaha', ('192.168.77.1', 8888))
recv_msg = recv_data[0]
send_addr = recv_data[1]
# print("%s 发送了:%s" % (str(send_addr), recv_msg.decode("utf-8"))) # linux发送的数据用utf8解码
print("%s 发送了:%s" % (str(send_addr), recv_msg.decode("gbk"))) # windows发送的数据用gbk解码
udp_socket.close()
if __name__ == "__main__":
main()
udp接发数据总结
发送数据的流程:
- 创建套接字
- 发送数据
- 关闭套接字
接收数据的流程:
- 创建套接字
- 绑定本地自己的信息,ip和端口
- 接收数据
- 关闭套接字
端口绑定的问题
- 如果在你发送数据时,还没有绑定端口,那么操作系统就会随机给你分配一个端口,循环发送时用的是同一个端口;
- 也可以先绑定端口,再发送数据。
udp发送消息时自己绑定端口示例
import socket
def main():
# 创建一个udp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定端口
udp_socket.bind(('192.168.13.1', 8080))
while 1:
# 从键盘获取要发送的数据
send_data = input("请输入你要发送的数据:")
if send_data == "exit":
break
# 使用套接字收发数据
udp_socket.sendto(send_data.encode("utf-8"), ("193.168.77.1", 8080))
# 关闭套接字
udp_socket.close() # 按ctrl+c退出
if __name__ == "__main__":
main()
但应注意,同一端口在同一时间不能被两个不同的程序同时使用;
单工,半双工,全双工
单工半双工全双工的理解
单工:
只能单向发送信息,别人接收,别人不能回复消息,比如广播;
半双工:
两个人都能发消息,但是在同一时间只能有一个人发消息,比如对讲机;
全双工:
两个人都能发消息,能同时发,比如打电话;
udp使用同一套接字收且发数据
"""socket套接字是全双工"""
import socket
def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(('192.168.13.1', 8080))
# 让用户输入要发送的ip地址和端口
dest_ip = input("请输入你要发送数据的ip地址:")
dest_port = int(input("请输入你要发送数据的端口号:"))
# 从键盘获取要发送的数据
send_data = input("请输入你要发送的数据:")
# 使用套接字收发数据
udp_socket.sendto(send_data.encode("utf-8"), (dest_ip, dest_port))
# 套接字可以同时 收发数据;
recv_data = udp_socket.recvfrom(1024)
print(recv_data)
# 关闭套接字
udp_socket.close() # 按ctrl+c退出
if __name__ == "__main__":
main()
在这里体现不出来socket是全双工,因为现在解释器只能按照流程,一步一步走下去,后面学习了进程线程协程就可以做到了。
tcp
tcp-可靠传输
tcp采取的机制
- 采用发送应答机制
- 超时重传
- 错误校验
- 流量控制和阻塞管理
tcp与udp的区别
- tcp更安全可靠,udp相对没那么安全可靠;
- 面向连接
- 有序数据传输
- 重发丢失的数据
- 舍弃重复的数据包
- 无差错的数据传输
- 阻塞/流量控制
tcp,udp应用场景
tcp应用场景:下载,发送消息
udp应用场景:电话,视频直播等
tcp客户端
tcp客户端发送数据
import socket
def main():
# 1.创建tcp的套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.链接服务器
tcp_socket.connect(('193.168.11.1', 8080))
# 3.发送/接收消息
send_data = input("请输入你要发送的消息:")
tcp_socket.send(send_data.encode("utf-8"))
# 4.关闭套接字
tcp_socket.close()
if __name__ == "__main__":
main()
tcp服务器
监听套接字,专门用来监听的;
accept会对应新创建的套接字,当监听套接字收到一个请求后,将该请求分配给新套接字,由此监听套接字可以继续去监听了,而新套接字则为该胡克段服务。
import socket
def main():
# 创建tcp套接字
tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_service_socket.bind(('', 8080))
# 让默认的套接字由主动变为被动
tcp_service_socket.listen(128)
# 等待客户端的链接
new_client_socket, client_addr = tcp_service_socket.accept()
print("链接的客户端地址为:", client_addr)
# 接收客户端发送过来的请求
recv_data = new_client_socket.recvfrom(1024)
print(recv_data)
# 给客户端回送消息
new_client_socket.send("hahahah".encode("utf-8"))
new_client_socket.close()
tcp_service_socket.close()
if __name__ == '__main__':
main()
listen里面的参数,表示同时只允许128个链接访问。
QQ不绑定端口的运行原理-扩展
udp和tcp并用;
使用QQ,先登录,登录后告诉腾讯服务器此QQ运行的端口,发消息时,通过腾讯服务器转发给另一个QQ;
不绑定端口也有一个好处,就是允许多开,即一个电脑上可以运行多个QQ;
recv和recvfrom的区别
recvfrom里面不仅有发过来的数据,还有发过来数据的人的信息;
recv里面就只有数据;
tcp客户端服务端流程梳理
tcp服务器流程梳理
- 创建服务器套接字
- 绑定本地信息
- 让默认的套接字由主动变为被动
- 等待客户端的链接,堵塞
- 被客户端链接后,创建一个新的客服套接字为客户端服务;
- 接收客户端发送的消息,堵塞
- 接收客户端发送的消息后,给客户端回消息
- 关闭客服套接字,关闭服务端套接字
tcp注意点
tcp服务器一般情况下都需要綁定,否则客户端找不到这个服务器。
tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip, port等信息就好,本地客户端可以随机。
tcp服务器通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的。
当客户端需要链接服务器时,就需要使用connect进行链接, udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信。
当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务。
liston后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的。
关闭isten后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信。
关闭accept返回的套接字意味着这个客户端已经服务完毕。
9.当客户端的套接字调用close后.服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过 返回数据的长度来区别客户端是否已经下线。
tcp应用案例 ###
示例1-为一个用户办理一次业务:
"""可以理解为银行一个客服为排队的人员办理业务"""
import socket
def main():
# 1.创建tcp套接字
tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.绑定本地信息
tcp_service_socket.bind(('', 8080))
# 3.让默认的套接字由主动变为被动
tcp_service_socket.listen(128)
while 1:
# 4.等待客户端的链接
new_client_socket, client_addr = tcp_service_socket.accept()
print("链接的客户端地址为:", client_addr)
# 接收客户端发送过来的请求
recv_data = new_client_socket.recvfrom(1024)
print(recv_data)
# 给客户端回送消息
new_client_socket.send("hahahah".encode("utf-8"))
# 关闭套接字
new_client_socket.close()
tcp_service_socket.close()
if __name__ == '__main__':
main()
示例2-为同一用户服务多次并判断一个用户是否服务完毕:
"""可以理解为银行一个客服为排队的人员办理业务"""
import socket
def main():
# 1.创建tcp套接字
tcp_service_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.绑定本地信息
tcp_service_socket.bind(('', 8080))
# 3.让默认的套接字由主动变为被动
tcp_service_socket.listen(128)
while 1:
# 4.等待客户端的链接
new_client_socket, client_addr = tcp_service_socket.accept()
print("链接的客户端地址为:", client_addr)
# 循环目的:为同一个客户服务多次
while 1:
# 接收客户端发送过来的请求
recv_data = new_client_socket.recvfrom(1024)
print(recv_data)
# 如果recv解堵塞,那么有两种方式
# 1.客户端发了数据过来
# 2.客户端调用了close
if recv_data:
# 给客户端回送消息
new_client_socket.send("hahahah".encode("utf-8"))
else:
break
# 关闭套接字
new_client_socket.close()
tcp_service_socket.close()
if __name__ == '__main__':
main()
示例3-tcp文件下载客户端和服务端:
文件下载客户端
import socket
def main():
# 1.创建套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.获取服务器的ip,port
dest_ip = input("请输入你要链接的服务器ip:")
dest_port = input("请输入你要链接的端口:")
# 3.链接服务器
tcp_socket.connect((dest_ip, dest_port))
# 4.获取下载的文件名字
want_file = input("请输入你要下载的文件:")
# 5.将文件名字发送到服务器
tcp_socket.send(want_file.encode("utf-8"))
# 6.接收要下载的文件
file_data = tcp_socket.recv(1024)
# 7.将接收文件的数据写入一个文件中
if file_data:
with open("[复件]" + want_file, "wb") as f:
f.write(file_data)
# 8.关闭套接字
tcp_socket.close()
pass
if __name__ == '__main__':
main()
文件下载服务端
import socket
def send_file2client(new_socket, client_addr):
# 1.接受客户端发送过来的 要下载的文件名
want_file = new_socket.recv(1024).decode("utf-8")
print("客户端 %s 要接收的文件为:%s" % (str(client_addr), want_file))
# 2.读取文件数据
file_data = None
try:
f = open(want_file, "rb")
file_data = f.read()
f.close()
except Exception as e:
print("你要下载的文件 %s 不存在" % want_file)
# 3.发送文件的数据给客户端
if file_data:
new_socket.send(file_data)
def main():
# 1.创建套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2.绑定本地信息
tcp_socket.bind(('', 8080))
# 3.套接字被动接受 listen
tcp_socket.listen(128)
while 1:
# 4.等待客户端的链接 accept
new_socket, client_addr = tcp_socket.accept()
# 5.调用函数发送文件到客户端
send_file2client(new_socket, client_addr)
# 7.关闭套接字
new_socket.close()
tcp_socket.close()
if __name__ == '__main__':
main()
Python进阶之网络编程的更多相关文章
- python进阶之 网络编程
1.tcp和udp协议的区别 TCP协议 面向连接\可靠\慢\对传递的数据的长短没有要求 两台机器之间要想传递信息必须先建立连接 之后在有了连接的基础上,进行信息的传递 可靠 : 数据不会丢失 不会重 ...
- python高级之网络编程
python高级之网络编程 本节内容 网络通信概念 socket编程 socket模块一些方法 聊天socket实现 远程执行命令及上传文件 socketserver及其源码分析 1.网络通信概念 说 ...
- 第六篇:python高级之网络编程
python高级之网络编程 python高级之网络编程 本节内容 网络通信概念 socket编程 socket模块一些方法 聊天socket实现 远程执行命令及上传文件 socketserver及 ...
- Python进阶:函数式编程实例(附代码)
Python进阶:函数式编程实例(附代码) 上篇文章"几个小例子告诉你, 一行Python代码能干哪些事 -- 知乎专栏"中用到了一些列表解析.生成器.map.filter.lam ...
- Python之路 - 网络编程之粘包
Python之路 - 网络编程之粘包 粘包
- Python之路 - 网络编程初识
Python之路 - 网络编程初识 前言
- Python进阶之面向对象编程
面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机 ...
- 周末班:Python基础之网络编程
一.楔子 你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运行,你就会发现,这两个python的文件分别运行的很好.但是如果这两个程序之间想要传递一个数据, ...
- python之路——网络编程
一.楔子 你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运行,你就会发现,这两个python的文件分别运行的很好.但是如果这两个程序之间想要传递一个数据, ...
随机推荐
- Apereo CAS Server服务端搭建教程
不说废话了,直接看搭建过程吧. 首先到下载源码,https://github.com/apereo/cas-overlay-template/tree/4.2 附上地址,本次版本为4.2,下载源码后如 ...
- iOS 自建企业级应用(In-House)分发平台
注意事项 自建分发平台,首先需要有一个可以提供下载功能的服务器,而且服务器需要支持HTTPS协议! 其实,使用七牛云就可以完成这些操作. 推荐方案 七牛云实践方案简述(感兴趣的朋友可以和我交流具体的实 ...
- the little schemer 笔记(2)
第二章 Do it, Do it Again, and Again, and Again... 假设l是 (Jack Sprat could eat no chicken fat) 那么 (lat? ...
- django 相关问题
和数据库的连接 session的实现 django app开发步骤 python环境准备 数据库安装 model定义 url mapping定义 view定义 template定义 如何查看数据库里的 ...
- 如何改变CSV文件的编码
通常我.csv文件的编码都不是我们想要的,比如我要把他保存为Utf-8格式的,好让我可以导入数据库,不乱码 工具/原料电脑,.csv文件方法/步骤1首先,将.csv文件保存一下.然后鼠标右击打开方式记 ...
- Python实现决策树ID3算法
主要思想: 0.训练集格式:特征1,特征2,...特征n,类别 1.采用Python自带的数据结构字典递归的表示数据 2.ID3计算的信息增益是指类别的信息增益,因此每次都是计算类别的熵 3.ID3每 ...
- Xml文档数据提取到Excel表中
近期,财务一位同事,吐槽:<某XX开票软件>导出数据文档只有Xml格式,竟然没有Excel文档,工作起来非常不方便,希望我想想办法.上图: 需求分析:Xml数据----> 提取到Da ...
- 关于Control.Dispatcher.BeginInvoke卡界面
Control.Dispatcher.BeginInvoke里的逻辑由UI线程执行,如果内部包含耗时操作就会造成界面卡住. Action.BeginInvoke里的逻辑,将在一个新开的线程中执行,而不 ...
- iOS 网络开发
http://www.cnblogs.com/kenshincui/p/4042190.html
- laravel核心思想
服务容器.依赖注入.门脸模式 服务容器 容器概念 用来装一个个实例的对象,比如邮件类. IOC控制反转 IOC(Inversion of Control)控制反转,面向对象,可降低代码之间的耦合度,借 ...