python高级编程
1 IP地址
用来在网络中标记一台电脑;在本地局域网上是唯一的。
2 端口
一个程序需要收发网络数据,就需要端口号。
3 socket
创建socket
# 创建tcp socket
import socket
s = socket.socket(AddressFamily, Type)
说明:
函数socket.scoket
创建一个socket
,该函数带有两个参数:
AddressFamily
:
Type
:tcp
或者udp
发送tcp
数据:
import socket
# 创建tcp的套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 使用套接字
# 关闭套接字
s.close()
udp网络
发送udp
数据:
import socket
# 创建upp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ip_port = (
"192.168.0.122",
8080
)
content = input("请输入内容:")
# 发送内容
# udp_socket.sendto("hahahah", 对方的ip和port号)
udp_socket.sendto(content.encode("utf-8"), ip_port)
# 关闭udp套接字
udp_socket.close()
接收udp
数据:
import socket
# 创建udp套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 绑定自己的ip地址,端口号
localaddr = ("", 4040)
udp_socket.bind(localaddr)
# 接收数据
# recv_data是一个元组,其中包含所接收到的信息和发送方的ip地址、端口号
recv_data = udp_socket.recvfrom(1024) # 1024表示本次接收的最大数据
recv_msg = recv_data[1].decode("gbk") # 收到的信息是windows发来的,就用gbk
# 关闭套接字
udp_socket.close()
一个套接字是可以同时收发数据的。
tcp网络
tcp
协议,传输控制协议。
tcp
与udp
的不同点:
- 1.面向连接(连接已创建才会传输)
- 2.有序数据传输
- 3.重发丢失的数据包
- 4.舍弃重复的数据包
- 5.无差错的数据传输
- 6.阻塞、流量控制
tcp
客户端
构建流程
import socket
# 创建tcp套接字
tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 链接服务器
server_ip = "127.0.0.1"
server_port = 8080
tcp_socket.connect((server_ip, server_port))
# 发送数据/接收数据
send_msg = "cjh"
tcp_socket.send(send_msg.encode("utf-8"))
# 关闭套接字
tcp_socket.close()
tcp
服务器
构建流程
import socket
# 创建套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 绑定服务器ip、port
tcp_server_socket.bind(("", 4040))
# 让默认的套接字由主动变为被动listen,这样就可以接收别人的连接
tcp_server_socket.listen(128)
# 如果有新的客户端来连接服务器,那么就产生一个新的套接字专门为这个客户端服务
# new_client_socket用来为这个客户端服务
# clientAddr客户端的地址
# tcp_server_socket就可以省下来专门等待其他新的客户端连接
new_client_socket, clientAddr = tcp_server_socket.accept()
# 接收客户端发来的信息
recv_data = new_client_socket.recv(1024)
# 回送数据给客户端
new_client_socket.send("hello".encode("utf-8"))
# 关闭套接字
new_client_socket.close()
tcp_server_socket.close()
77
tcp`注意点
-
tcp
服务器一般情况下都需要绑定ip
和port
。 -
tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动,这是做tcp服务器必须要做的。5阿
-
tcp_server_socket.setblocking(False) 给套接字设置为非堵塞方式
4多任务-线程
即操作系统可以同时运行多个任务。
线程
创建线程
import threading
import time
def sing():
for i in range(5):
print("--sing--")
time.sleep(1)
# 创建线程对象
t = threading.Thread(target=sing)
# 执行线程对象(生成的新线程)
t.start()
通过继承Thread类创建线程
import threading
import time
class MyThread(threading.Thread):
def run(self):
for i in range(5):
print("----audiA5----")
time.sleep()
t = MyThread()
t.start() # 会自动调用run方法
多个子线程会共享全局变量。
target
指定将来这个线程去哪里执行代码
args
指定将来调用函数的时候传递什么数据过去。args
是一个元组。
同步
协同步调,按预定的先后次序进行运行。
互斥锁
当多个线程几乎同时修改某一个共享数据时,需要进行同步控制。
线程同步能够保证多个线程安全访问竞争资源,最简单的机制就是引入互斥锁。
某个线程要更改共享资源时,先将其锁定,此时资源的状态为“锁定”,其他线程就不能更改,直到该线程释放资源后将资源变为“非锁定”,其他线程才能再次锁定该资源。
互斥锁保证了每次只有一个线程进入写入操作,保证了多线程情况下数据的正确性。
# 创建互斥锁
mutex = threading.Lock()
# 上锁
mutex.acquire()
# 解锁
mutex.release()
死锁
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
避免死锁
- 添加超时时间。
- 银行家算法。
5多任务-进程
进程的创建
import multiprocessing
p = multiprocessing.Process(target=test)
p.start()
进程和线程的对比
一个进程中可以有多个线程。
进程之间的通信
Queue队列
import multiprocessing
# 创建队列 其中的3表示最大可存放的数据量,不写的话由系统自行分配
q = multiprocessing.Queue(3)
# 写入数据
q.put(11)
# 取数据
q.get()
# 队列是否为空 False未空 True已空
q.empty()
# 队列是否已满 False未满 True已满
q.full()
进程池Pool
创建进程池
import multiprocessing
# 定义一个进程池,最大进程数为3
po = multiprocessing.Pool(3)
# apply_async(要调用的目标, (传递给目标的参数元组,))
po.apply_async(worker, (1,))
# 关闭进程池
po.close()
# 等待进程池中的所有子进程执行完成
po.join()
6 多任务-协程
迭代器
什么是迭代器
from collections import iterable
from collections import iterator
class Classmate(object):
def __init__(self):
self.names = list()
self.current_num = 0
def add(self, name):
self.names.append(name)
def __iter__(self):
"""一个对象如果成为可迭代对象,那么必须有__iter__方法"""
return self
def __next__(self):
if self.current_num < len(self.names):
self.current += 1
return self.names[self.current_num]
else:
raise StopIteration
# 创建实例
classmate = Classmate()
# 调用方法给names中添加元素
classmate.add("ccc")
classmate.add("aaa")
classmate.add("bbb")
# 因为Classmate类中拥有__iter__, __next__方法,因此它是一个迭代器,可以使用for
for name in classmate:
print(name)
迭代器的应用
可以减少内存空间
class Fibonacci(object):
"""迭代器生成斐波那契数列"""
def __init__(self):
self.num = 0
self.a = 0
self.b = 1
def __iter__(self):
return self
def __next__(self):
if self.num < 10:
self.num += 1
self.a, self.b = self.b, self.a + self.b
return self.a
else:
raise StopIteration
fibo = Fibonacci()
for i in fibo:
print(i)
生成器
特殊的迭代器。
def generator_demo(num):
a, b = 0, 1
current_num = 0
while True:
if current_num < num:
yield a # 如果函数中有yield语句,那这个就不再是函数,而是生成器模板
a, b = b, a+b
current_num += 1
# 如果调用的generator_demo中有yield语句,那么此时就是创建一个生成器对象
gen = generator_demo(10)
print(next(gen))
协程-yield
协程
import time
def task_1():
while True:
print("1")
time.sleep(0.1)
yield
def task_2():
while True:
print("2")
time.sleep(0.1)
yield
t1 = task_1()
t2 = task_2()
while True:
next(t1)
next(t2)
协程-gevent
import gevent
def f1(n):
for i in range(n):
print(i)
gevent.sleep(1)
g1 = gevent.spawn(f1, 5)
g2 = gevent.spawn(f1, 5)
g3 = gevent.spawn(f1, 5)
g1.join()
g2.join()
g3.join()
monkey.patch_all() # 将程序中用到耗时操作的代码全部更改为gevent中自己实现的模块
# 一般使用joinall一次性创建
gevent.joinall([
gevent.spawn(f1, 5)
gevent.spawn(f1, 5)
gevent.spawn(f1, 5)
])