资讯详情

python 学习

python 学习

开发常用网站

  • 博客园
  • csdn
  • 51cto
  • 开源中国
  • github
  • 知乎
  • 简书

1 网络编程

1-1 网络基本概念

  1. 基本概念
  • 数据共享
  1. IP地址
  • 值:192.168.0.0.1
  • 功能:在网络上标记计算机
  • 私有 ip 在众多网络中,国际规定有一部分IP地址用于我们的局域网,即私网IP,不再围为: 10.0.0.0~10.255.255.255 172.16.0.0~172.31.255.255 192.168.0.0.0~192.168.255.255

    注意: IP 地址 127.0.0.1 ~ 127.255.255.255 用于回路测试

  1. Linux、Windows查看网卡信息
  • Linux
    • sudo ifconfig ens40 up/down
  • Windows
    • ipconfig lo:本地网卡 ens40:外网网卡
  1. IP地址的分类-ipv4和ipv6介绍
  • ipv4 : 0-255.0-255.0-255.1-255 192.168.0.0.1
    • A 0
    • B 10
    • C 110
    • D 1110 多点广播
    • E 11110 保留

0/255 不能用;1-254用

类型 网络号 网络号
A 0******* .********
B 10******.********
C 110*****. ********
  • ipv6 fe80::4a3:4ee2:d0cd:f011
  1. (重点)端口
  • 给出哪个过程? port
  • 端口用端口号标记,端口号用程序标记。
  1. 端口分类:知名端口、动态端口 端口号不是随意使用的,而是按照一定的规定分配的。
  • 知名端口:0~1023
  • 动态端口:1024~65535
  1. socket介绍
  • 以前如何通信不同电脑上的过程?
  • 创建 socket
import socket # 创建 tcp 套接字 s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # ... 这里使用套接字的功能(省略)... # 不使用时,关闭套接字 s.close()  # 创建 udp 套接字 s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # ... 这里使用套接字的功能(省略)... # 不使用时,关闭套接字 s.close() 

说明: 套接字的使用过程与文件的使用过程非常相似 1.创建套接字 2.使用套接字收/发数据 三、关闭套接字

1-2 udp 用户数据报告协议

运行模式

  • python3 ***.py 交互模式
  • python3
  • ipython3
  • (重点)udp 发送数据 demo
# demo #!/usr/bin/env python3 import socket   def main():     # 创建一个tcp套接字     udp_socket = socket.socket
       
        (socket
        .AF_INET
        ,socket
        .SOCK_DGRAM
        ) 
        # 从键盘发送数据 send_data 
        = 
        input
        (
        "请输入要发送的数据:"
        ) 
        # 可以使用套接字收发数据 
        # 元组 dest_ip / b"hhahah" 字符类型,加一个 b 转译 udp_socket
        .sendto
        ( send_data
        .encode
        (
        'utf-8'
        )
        , 
        (
        "10.10.22.68"
        , 
        8088
        )
        ) 
        # 关闭套接字 udp_socket
        .close
        (
        ) 
        if __name__ 
        == 
        "__main__"
        : main
        (
        ) 
        # demo-2 循环发 
        #!/usr/bin/env python3 
        import socket 
        def 
        main
        (
        )
        : 
        # 创建一个tcp套接字 udp_socket 
        = socket
        .socket
        (socket
        .AF_INET
        ,socket
        .SOCK_DGRAM
        ) 
        while 
        True
        : 
        # 从键盘发送数据 send_data 
        = 
        input
        (
        "请输入要发送的数据:"
        ) 
        # 如果输入的数据是 exit,那么久退出程序 
        if send_data 
        == 
        'exit'
        : 
        break
        ; 
        # 可以使用套接字收发数据 
        # 元组 dest_ip / b"hhahah" 字符类型,加一个 b 转译 udp_socket
        .sendto
        ( send_data
        .encode
        (
        'utf-8'
        )
        , 
        (
        "10.10.22.68"
        , 
        8088
        )
        ) 
        # 关闭套接字 udp_socket
        .close
        (
        ) 
        if __name__ 
        == 
        "__main__"
        : main
        (
        ) 
       
  • (重点)接收 udp 数据 注意:windows 的编码默认是 gbk
#!/usr/bin/env python3
import socket


def main():
  # 1 创建套接字
  udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
  # 2 绑定一个本地信息
  localaddr = ("",7788)
  udp_socket.bind(localaddr) # 必须绑定自己的 ip,以及 port
  # 3 接收数据
  while True:
    recv_data = udp_socket.recvfrom(1024) # 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("utf-8")))
    
  # 5 关闭套接字
  udp_socket.close()

if __name__ == "__main__":
    main()
  • 总结:udp 发送/接收 数据流程
udp 发送数据流程 udp 接收数据流程
1.绑定套接字 2.发送数据 3.关闭套接字 1.绑定套接字 2.绑定本地信息 3.接收打印数据 4.关闭套接字
  • (重点)端口绑定的问题
    1. 同一个端口不允许同一时刻,被用两次
    2. 发送方可以不绑定端口,接收方必须先绑定端口
  • 输入对方 ip、port、全双工、半双公、单工等
      • recvfrom 在数据没到来之前,会堵塞程序
      • 单工:只能收;
      • 半双工:能收发,不能同一时刻操作;
      • 全双工:同一时刻能收能发;
      • socket: 全双工
  • 案例:udp 聊天机器
#!/usr/bin/env python3
import socket

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


def recv_msg(udp_socket):
	"""接收数据"""
	recv_data = udp_socket.recvfrom(1024) # 1024 本次接收的最大字节数
	print("%s:%s" % (str(recv_data[1]), recv_data[0].decode("utf-8"))) # windows 是 gbk


def main():
	# 创建套接字
	udp_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)

	# 绑定信息
	udp_socket.bind(("",7788))

	# 循环来处理的事情
	while True:
    # 发送
		send_msg(udp_socket)
    # 接收
		recv_msg(udp_socket)
		

if __name__ == "__main__":
	main()

1-3 tcp 客户端 - 传输协议

  • 创建 tcp 套接字
  • ** 连接服务器 **
  • 发送/接收 数据
  • 关闭套接字
#!/usr/bin/env python3
import socket

def main():
	# 创建 tcp 套接字
	tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

	# 连接服务器
	server_ip = input("请输入服务器的ip:")
	server_port = int(input("请输入服务器的port:"))
	server_addr = (server_ip,server_port)
  tcp_client_socket.connect(server_addr)

	# 发送/接收 数据
	send_data = input("请输入发送的数据:")
	tcp_client_socket.send(send_data.encode("utf-8"))

	# 关闭套接字
	tcp_client_socket.close()


if __name__ == "__main__":
	main()

1-4 tcp 服务器

  • socket 创建一个套接字
  • bind 绑定 ip和port
  • listen 使套接字变为可以被动连接
  • accept 等待客户端的连接
  • recv/send 接收发送数据

监听套接字负责接收新的套接字 accept产生新的套接字,为客户服务

#!/usr/bin/env python3
import socket

def main():
  # 买个手机(创建套接字 socket)
  tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

  # 插入手机卡(绑定本地信息 bind)
  tcp_server_socket.bind("",7890)

  # 将手机设置为正常的接听状态 (让默认的套接字由主动变为被动 listen)
  tcp_server_socket.listen(128) # 128同一时刻客户端连接服务器的数量

  # 循环为多个客户端服务
  while True:
    print("等待一个新的客户端的到来。。。")
    # 等待别人的电话的到来(等待客户端的连接 accept)
    new_client_socket,client_addr = tcp_server_socket.accept()

    print("一个新的客户端已经到来%s" % str(client_addr))

    # 循环多次为同一个客户端服务多次
    while True:
      # 接收对方发来的数据
      revc_data = new_client_socket.recv(1024) # 接收1024个字节
      print("客户端发送过来的请求是:%s" % recv_data.decode('gbk'))

      # 如果 recv 解堵塞,那么有2种方式
      # 1. 客户端发送过来数据
      # 2. 客户端调用close导致了 recv 解堵塞
      if revc_data:
        # 回送一部分数据给客户端
        new_client_socket.send("thank you!".encode('gbk'))
      else:
        break

    # 关闭accept返回的套接字,意味着不会再为这个客户端服务
    new_client_socket.close()
    print("已经服务完毕。。。")

  # 如果将监听套接字关闭了,那么会导致不能再吃等待客户端的到来,即 xxxx.accept就会失败
  tcp_server_socket.close()


if __name__ == "__main__":
  main()

1-5 tcp 下载文件

文件下载器

#!/usr/bin/env python3
#coding:utf-8
# client
import socket,os
def 

def main():
  # 创建套接字
  tcp_socket = socket.socket()
  # 获取服务器的 ip port
  tcp_socket.connect()
  # 连接服务器

  # 将文件名字发送到服务器
  file_name = input("请输入文件名称:")
  # 接收文件数据

  # 保存接收数据到一个文件中

  # 关闭套接字


if __name__ == "__main__":
  main()
#!/usr/bin/env python3
# coding:utf-8
# server
import socket,os
def 

def main():


if __name__ == "__main__":
  main()

udp 与 tcp udp: 写信的模型,不安全 tcp: 打电话的模型,比较安全;比较稳定; 采用发送应答机制 — 对比 —

UDP TCP
是否连接 无连接 面向连接
是否可靠 不可靠传输,不使用流量控制和拥塞控制 可靠传输,使用流量控制和拥塞控制
连接对象个数 支持一对一,一对多,多对一和多对多交互通信 只能是一对一通信
传输方式 面向报文 面向字节流
首部开销 首部开销小,仅8字节 首部最小20字节,最大60字节
适用场景 适用于实时应用(IP电话、视频会议、直播等) 适用于要求可靠传输的应用,例如文件传输
udp tcp
客户端流程 socket\bind\sendto/recvfrom\close socket\connect\send/recv\close
服务端流程 socket\bind\listen\accept\recv/send\close

tcp 总结

  1. tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
  2. tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
  3. tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
  4. 当客户端需要链接服务器时,就需要使用connect进行连接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
  5. 当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
  6. listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
  7. 关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信
  8. 关闭accept返回的套接字意味着这个客户端已经服务完毕
  9. 当客户端的套接字调用close后,服务端会recv解堵塞,并且返回的长度为0,因此可以通过返回数据的长度来区别客户端是否已经下线

2 多任务

简介

  • 多任务 什么叫“多任务”,简单地说,就是操作系统可以同时做多个任务。
  • 单核CPU 要实现多任务,通过调度算法实现,如:时间片轮转、优先级调度等;四核CPU相当于4个单核CPU。
  • 并发: 任务量大于CPU核数,通过操作系统的各种调度算法,实现多个任务“一起”执行(实际上由于切换任务的速度非常快,只是看上去一起执行,并没有真正的同时执行。)
  • 并行: 任务量小于等于CPU核数,级任务是真正的一起执行的。
  • 进程 进程是具有一定独立功能的程序(就是一坨代码,还没有运行时叫程序)关于某个数据集合上的一次运行活动 (是运行的程序),进程是系统进行资源分配的单位。
  • 线程 线程是进程的一个实体,是CPU调度的单位 ,它是比进程更小的能独立运行的基本单位。线程基本上不拥有系统资源,只拥有一点运行中必不可少的资源(如:程序计数器、一组寄存器和栈)。 进程和线程之间的关系: 举个简单的例子:一个手机中运行了好多后台的APP程序,如微信、QQ、支付宝…,其中,一个进程就是运行中的QQ,而QQ中可以跟不同的人进行聊天,每个聊天的窗口就是一个线程,你可以同时跟好多人聊天(即,开好多个聊天窗口,也就是说一个进程中可以由好多线程 ),但是当一个聊天窗口卡死了,QQ就不能运行了(一个线程死掉就等于整个进程死掉 ),只能强制把它关了然后重启,但是你QQ挂了,并不影响你的微信和支付宝的运行(进程有独立的地址空间,一个进程崩溃后,不会对其他进程产生影响 ),同时你可以在不同的聊天窗口发送相同的QQ表情包,但是你不能在微信里发送QQ里的表情包(同进程里的多线程之间共享内存数据,不同进程之间是相互独立的,各有个的内存空间 )。
#!/usr/bin/env python3
#coding=utf-8
import threading
import time


def sing():
	"""唱歌5秒钟"""
	for i in range(5):
		print("---唱歌---")
		time.sleep(1)

def dance():
	"""跳舞5秒钟"""
	for i in range(5):
		print("---跳舞---")
		time.sleep(1)

def main():
	t1 = threading.Thread(target=sing) # 注意:不能写成 sing();加括号是调用函数,不加括号是找到函数的位置
	t2 = threading.Thread(target=dance)
	t1.start()
	t2.start()

if __name__ == "__main__":
	main()

2-1 线程

  1. 线程的运行是没有先后顺序的
  2. 查看程序中所有线程数量:threading.enumerate()
  3. 当调用Thread的时候,不会创建线程;调用start才会运行子线程
  4. 延时的话可以保证先运行哪个程序,再运行哪个程序

线程创建的两种方法:

  • Thread(target=函数名);简单优先使用
  • 通过继承Thread类完成创建线程;必须定义 run 方法
#!/usr/bin/env python3
#coding=utf-8
import threading
import time


def test1():
	for i in range(5):
		print("----test1---%d---" % i)
		time.sleep(1)

	# 如果创建Thread时执行的函数,运行结束那么意味着 这个子线程结束了....

def main():
	# 在调用Thread之前先打印当前线程信息
	print(threading.enumerate())
	t1 = threading.Thread(target=test1)

    # 在调用Thread之后打印
	print(threading.enumerate())

	t1.start()

    # 在调用start之后打印
	print(threading.enumerate())


if __name__ == "__main__":
	main()

#!/usr/bin/env python3
#coding=utf-8
import threading
import time


def test1():
	for i in range(5):
		print("----test1---%d---" % i)
		time.sleep(1)

	# 如果创建Thread时执行的函数,运行结束那么意味着 这个子线程结束了....

def test2():
	for i in range(10):
		print("----test2---%d---" % i)
		time.sleep(1)

def main():
	t1 = threading.Thread(target=test1)
	t2 = threading.Thread(target=test2)

	t1.start()
	t2.start()

	while True:
		if len(threading.enumerate()) == 1:
			break;
		print(threading.enumerate())
		time.sleep(1)

if __name__ == "__main__":
	main()

import threading
import time


# 通过继承 Thread 类完成创建线程
class MyThread(threading.Thread):
  def run(self):
    for i in range(3):
      time.sleep(1)
      msg = "I'm"+self.name+'@'+str(i) # name属性中保存的是当前线程的名字
      print(msg)

    self.login()

  def login(self):
    print("---login---")

if __name__ == '__main__':
  t = MyThread()
  t.start()

  • 多线程共享全局变量 在一个函数中对全局变量进行修改的时候,到底是否需要使用global进行说明。 要看是否对全局变量的执行指向进行了修改, 如果修改了执行,即让全局变量指向了一个新的地方,那么必须使用 global 如果,仅仅是修改了指向空间中的数据,此时不用必须使用global
import threading
import time

g_num = 100

def test1():
	global g_num
	g_num += 1
	print("---in test1 g_num=%d ---" % g_num)

def test2():
    print("---in test2 g_num=%d ---" % g_num)

def test3(temp):
	temp.append(33)
	print("---in test3 g_num=%s ---" % str(temp))

g_nums = [11, 22]
def main():
	# target 指定将来 这个线程去那个函数执行代码
	# args 指定将来调用函数的时候传递什么数据过去
	t1 = threading.Thread(target=test1)
	t2 = threading.Thread(target=test2)
	t3 = threading.Thread(target=test3, args=(g_nums,))  # 元组

	t1.start()
	time.sleep(1)

	t2.start()
	time.sleep(1)

	t3.start()

	print("---in main thread g_num=%d ---" % g_num)


if __name__ == "__main__":
	main()

  • 创建线程时指定传递的参数、多线程共享全局变量的问题
    1. 资源竞争
import threading
import time

# 假设两个线程t1和t2都要对全局变量g_num(默认是0)进行加1运算,t1和t2都各对g_num加10次,g_num的最终的结果应该为20。

# 但是由于是多线程同时操作,有可能出现下面情况:

# 1、在g_num=0时,t1取得g_num=0。此时系统把t1调度为”sleeping”状态,把t2转换为”running”状态,t2也获得g_num=0
# 2、然后t2对得到的值进行加1并赋给g_num,使得g_num=1
# 3、然后系统又把t2调度为”sleeping”,把t1转为”running”。线程t1又把它之前得到的0加1后赋值给g_num。
# 4、这样导致虽然t1和t2都对g_num加1,但结果仍然是g_num=1

g_num = 0

def test1(num):
	global g_num
	for i in range(num):
		g_num += 1
	print("---in test1 g_num=%d ---" % g_num)

def test2(num):
	global g_num
	for i in range(num):
		g_num += 1
	print("---in test2 g_num=%d ---" % g_num)

def main():
	"""开启两个线程,修改同一个全局变量"""
	t1 = threading.Thread(target=test1, args=(1000000,))
	t2 = threading.Thread(target=test2, args=(1000000,))

	t1.start()
	t2.start()

	time.sleep(5)

	print("---in thread g_num=%d ---" % g_num)


if __name__ == "__main__":
	main()
  • 同步概念、互斥解决资源竞争的问题 上锁的代码越少越好

    • 同步概念 同步就是协同步调,按预定的先后次序进行运行,如:你说完,我再说。 ‘同’字从字面上容易理解为一起动作 其实不是,‘同’字应是指协同,协助,互相配合。

    • 互斥锁 当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制。 线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。 类似于数据库操作的事务。 互斥锁为资源引入一大状态:锁定/非锁定

    某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改; 直到该线程释放资源,将资源的状态变成”非锁定“,其他的线程才能再次锁定该资源。 互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。 基本操作: 创建锁

标签: 电流变送器cd195u

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台