源码打包
- 为什么打包源码
如果你想让你的实现的python代码,通过pip install 方式供所有人进行下载;那就需要将代码上传到PyPi上,这样才能让所有人使用;
如何打包源码上传:
1、有一个pypi官网账号;注册地址
2、更新pip版本到最新:py -m pip install --upgrade pip
3、通过pip安装twine:要使用twine来上传代码;
4、安装编译工具:pip install --upgrade build
- 创建项目结构:
第一步,创建本地目录结构;
daletou/ └── src/ └── daletou/ ├── __init__.py └── dlt.py
以上除了src和__init__.py为固定值,其他都可以自定义;目录结构需保持一致;
其中__init__.py是为了将目录作为包导入,默认可以为空。
dlt.py是包中的一个模块,主要是提供的功能供下载人调用
如在dlt.py中输入如下代码:
代码中提供的一个函数,返回指定的字符串;
此功能是最终上传的pypi后提供给外部的方法;
from random import sample def random_dlt(num=1,reds_pre=None,blue_pre=None): result = [] for n in range(num): if reds_pre is None: reds = sample([n for n in range(1,36)],5) if blue_pre is None: blues = sample([n for n in range(1,13)],2) reds.sort() blues.sort() result.append(' '.join(red_balls) + ' + '+ ' '.join(blue_balls)) return '\n'.join(result)
第二步:创建上传所需的文件;
最终得文件结构如下:
daletou/ ├── LICENSE ├── pyproject.toml ├── README.md ├── setup.py ├── src/ │ └── daletou/ │ ├── __init__.py │ └── dlt.py
- 文件说明:
pyproject.toml告诉构建工具构建项目所需的内容。
打开pyproject.toml并输入以下内容:
[build-system] requires = ["setuptools>=42"] build-backend = "setuptools.build_meta"
README.md 是包的描述信息,markdown格式书写;
1. # study Package 2. This is a simple study package.
setup.py是setuptools的构建脚本。它告诉 setuptools 您的包(例如名称和版本)以及要包含的代码文件。
打开setup.py并输入以下内容。更改name 以包含您的用户名;这可确保您拥有唯一的包名称,并且您的包不会与其他人按照本教程上传的包冲突。
import setuptools with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read() setuptools.setup( name="daletou", version="0.0.1", author="Author", author_email="author@example.com", description="example package", long_description=long_description, long_description_content_type="text/markdown", #url="", #project_urls={}, package_dir={"": "src"}, packages=setuptools.find_packages(where="src"), python_requires=">=3.6", )
部分属性说明:
name是您的包的分发名称。这可以是任何名称;
version是包版本。
author并author_email用于标识包的作者。
description是一个简短的、一句话的包摘要。
long_description是包的详细说明。
long_description_content_type: 描述使用什么类型的标记。
url是项目主页的 URL。可不写。
project_urls 显示的任意数量的链接。通常是文档、问题跟踪器等。
package_dir是一个字典,src目录被指定为根包。
packages 包含在分发包中的所有 Python导入包的列表;
python_requires给出项目支持的 Python 版本。
还有有个配置文件setup.cfg,相对于setup.py,此文件配置是静态元数据,内容基本不变;推荐使用setup.py配置;
具体可参考pypi官网解释;
LICENSE是许可文件,参考以下输入既可;
Copyright (c) 2018 The Python Packaging Authority Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- 编译打包:
在pyproject.toml文件同级目录;打开命令行工具;
执行命令:
python -m build
- 源码上传:
首先执行命令
twine check dist/*
检查是否存在问题,有问题提示,需要解决;
若无问题;执行以下命令上传;
twine upload dist/*
检查是否存在问题,有问题提示,需要解决;
若无问题;执行以下命令上传;
twine upload dist/*
网络编程
1、网络编程基础:
Sockets(套接字)可以在一个进程内,在同一机器上的进程之间,或者在不同主机的进程之间进行通信,主机可以是任何一台有连接互联网的机器。
Socket主要是使用IP地址,协议,端口号来标识一个进程。端口号的范围为0~65535(用户端口号一般大于1024),协议有很多种,经常用到的就是TCP,IP,UDP等;
2、python中的内置库socket
- python中的socket库提供了处理公共传输的特定类,以及一个用于处理其余部分的通用接口。
- socket是内置库,无需安装;
3、导入方式:
import socket
4、使用socket;
创建服务端
import socket def server(): print('服务端启动') #创建Tcp/Ip套接字对象 s=socket.socket(socket.AF_INET,socket.SOCK_STREAM) #流式Socket #创建Udp/Ip套接字对象 #s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #数据报式Socket s.bind(('127.0.0.1',18080)) # 绑定地址 s.listen(3) # 建立最多3个链接 while True: conn,addr= s.accept() # 等待客户端连接 print('欢迎{}'.format(addr)) #打印访问的用户信息 while True: data=conn.recv(1024) dt=data.decode('utf-8') #接收一个1024字节的数据 print('服务端收到:',dt) aa=input('服务端发送:') if aa=='quit': conn.close() #关闭来自客户端的连接 s.close() #关闭服务器端连接 else: conn.send(aa.encode('utf-8')) #发送数据
创建客户端
import socket def client(): import sys print('客户端启动') c=socket.socket() # 创建socket对象 c.connect(('127.0.0.1',18080)) print(c.getpeername())#获取远程的地址 #跟服务端建立连接 while True: ab=input('客户端发送:') if ab=='quit': c.close() #关闭客户端连接 sys.exit(0) else: c.send(ab.encode('utf-8')) #发送数据 data=c.recv(1024) #接收一个1024字节的数据 print('客户端收到:',data.decode('utf-8')) #输出接收的信息
先启动服务端,在启动客户端,实现简单通信功能
5、以上只能实现单一通信,发送后必须等待接收,实现群聊的需要使用到多线程;
使用UDP通信
创建群聊服务端:
#群聊服务端 def serverMany(): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建socket对象 addr = ('127.0.0.1', 9999) s.bind(addr) # 绑定地址和端口 print('服务端启动,地址:',addr) user = {} # 存放字典{addr:name} while True: try: data, addr = s.recvfrom(1024) # 等待接收客户端消息存放在2个变量data和addr里 if not addr in user: # 如果addr不在user字典里则执行以下代码 for address in user: # 从user遍历数据出来address s.sendto(data + ' 进入聊天室...'.encode('utf-8'), address) # 发送user字典的data和address到客户端 user[addr] = data.decode('utf-8') # 接收的消息解码成utf-8并存在字典user里,键名定义为addr continue # 如果addr在user字典里,跳过本次循环 if 'EXIT'.lower() in data.decode('utf-8'):#如果EXIT在发送的data里 name = user[addr] #user字典addr键对应的值赋值给变量name user.pop(addr) #删除user里的addr for address in user: #从user取出address s.sendto((name + ' 离开了聊天室...').encode(), address) #发送name和address到客户端 else: print('"%s" from %s:%s' %(data.decode('utf-8'), addr[0], addr[1])) for address in user: #从user遍历出address if address != addr: #address不等于addr时间执行下面的代码 s.sendto(data, address) #发送data和address到客户端 except ConnectionResetError: print('服务端异常')
创建客户端;
name = '用户昵称' def recv(sock, addr): ''' 一个UDP连接在接收消息前必须要让系统知道所占端口 也就是需要send一次,否则win下会报错 ''' sock.sendto(name.encode('utf-8'), addr) while True: data = sock.recv(1024) print(data.decode('utf-8')) def send(sock, addr): ''' 发送数据的方法 参数: sock:定义一个实例化socket对象 server:传递的服务器IP和端口 ''' while True: string = input('正在输入:') message = name + ' : ' + string data = message.encode('utf-8') sock.sendto(data, addr) if string.lower() == 'EXIT'.lower(): break def main(): import threading global name name = input('请输入你的名称:') ''' 主函数执行方法,通过多线程来实现多个客户端之间的通信 ''' s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server = ('127.0.0.1', 9999) tr = threading.Thread(target=recv, args=(s, server), daemon=True) ts = threading.Thread(target=send, args=(s, server)) tr.start() ts.start() ts.join() s.close() main()