Python文件的读写、正则表达式的运用、多线程与多进程、网络编程
文章目录
- 文件的读写
- 读文件
- 写文件
- 写二进制文件
- 读写``JSON``文件
- 正则表达式
- 常用的元字符
- 字符转义
- 重复
- 字符类
- 分支条件
- 分组
- 反义
- 反向引用
- 多重继承
- 多线程
- 守护线程
- 线程保护
- 多进程
- 网络编程
- 图片编程
- 邮件发送
- 发送普通邮件
- 发送附件
文件的读写
Python中实现文件的读写操作其实非常简单,通过Python内置的open
函数,我们可以指定文件名、操作模式、编码信息等来获得操作文件的对象,接下来就可以对文件进行读写操作了
操作模式 | 具体含义 |
---|---|
'r'
|
读取 (默认) |
'w'
|
写入(会先截断之前的内容) |
'x'
|
写入,如果文件已经存在会产生异常 |
'a'
|
追加,将内容写入到已有文件的末尾 |
'b'
|
二进制模式 |
't'
|
文本模式(默认) |
'+'
|
更新(既可以读又可以写 |
读文件
读取文本文件时,需要在使用open
函数时指定好带路径的文件名(可以使用相对路径或绝对路径)并将文件模式设置为'r'
(如果不指定,默认值也是'r'
),然后通过encoding
参数指定编码(如果不指定,默认值是None,那么在读取文件时使用的是操作系统默认的编码),如果不能保证保存文件时使用的编码方式与encoding参数指定的编码方式是一致的,那么就可能因无法解码字符而导致读取失败。
def main():f=open('再别康桥.txt','r',encoding='utf-8')print(f.read())f.close()
如果open
函数指定的文件并不存在或者无法打开,那么将引发异常状况导致程序崩溃。为了让代码有一定的健壮性和容错性,我们可以使用Python的异常机制对可能在运行时发生状况的代码进行适当的处理。
def main():try:f = open('再别康桥.txt', 'r', encoding='utf-8')print(f.read())except FileNotFoundError:print('无法打开指定文件!')except LookupError:print('指定了未知的编码!')except UnicodeDecodeError:print('读取文件时解码错误?!')finally:f.close()
if __name__ == '__main__':main()
在Python中,我们可以将那些在运行时可能会出现状况的代码放在try
代码块中,在try
代码块的后面可以跟上一个或多个except
来捕获可能出现的异常状况。由于finally
块的代码不论程序正常还是异常都会执行到因此我们通常把finally
块称为“总是执行代码块”,它最适合用来做释放外部资源的操作。如果不愿意在finally
代码块中关闭文件对象释放资源,也可以使用上下文语法,通过with
关键字指定文件对象的上下文环境并在离开上下文环境时自动释放文件资源
def main():try:with open('再别康桥.txt','r',encoding='utf-8') as f:print(f.read())
if __name__=='__main__':main()
除了使用文件对象的read
方法读取文件之外,还可以使用for-in
循环逐行读取或者用readlines
方法将文件按行读取到一个列表容器中。
import timedef main():# 一次性读取整个文件内容with open('致橡树.txt', 'r', encoding='utf-8') as f:print(f.read())# 通过for-in循环逐行读取with open('致橡树.txt', mode='r') as f:for line in f:print(line, end='')time.sleep(0.5)print()# 读取文件按行读取到列表中with open('致橡树.txt') as f:lines = f.readlines()print(lines)if __name__ == '__main__':main()
写文件
在使用open
函数时指定好文件名并将文件模式设置为'w'
即可。注意如果需要对文件内容进行追加式写入,应该将模式设置为'a'
。如果要写入的文件不存在会自动创建文件而不是引发异常。
from math import sqrtdef is_prime(n):assert n > 0for factor in range(2, int(sqrt(n)) + 1):if n % factor == 0:return Falsereturn True if n == 1 else Falsedef main():filenames = ['a.txt', 'b.txt', 'c.txt']fs_list = []try:#把可能出状况(在执行有风险)的代码放到try代码保护执行for filename in filenames:fs_list.append(open(filename, 'w', encoding='utf-8'))for number in range(10000):if is_prime(number):if number < 100:fs_list[0].write(str(number) + '\n')elif number < 1000:fs_list[1].write(str(number) + '\n')else:fs_list[2].write(str(number) + '\n')except FileNotFoundError: #except可以写多个分别用于处理不同的异常情况 else finally只有一个print('打开文件时出错')except IOError:#如果try中出现了状况就通过except来铺货错误(异常)进行对应的处理print('读写文件时出错')else:pass#如果没有出状况那么可以把无风险的代码放到else中执行finally:print('释放文件资源')#此处是最好的释放外部资源的位置因为不管程序正常还是异常 这里的代码一定会执行for fs in fs_list:fs.close()print('程序执行结束')if __name__ == '__main__':main()
写二进制文件
def main():try:with open('123.jpg','rb') as fs1:date=fs1.read()with open('456.jpg','wb') as fs2:fs2.write(date)except FileNotFoundError as e:print(e)print('指定文件无法打开')except IOError:print('读写文件时出错')print('程序执行结束')
if __name__ == '__main__':main()
读写JSON
文件
json
模块主要有四个比较重要的函数,分别是:- dump - 将Python对象按照JSON格式序列化到文件中
- dumps - 将Python对象处理成JSON格式的字符串
- load - 将文件中的JSON数据反序列化成对象
- loads - 将字符串的内容反序列化成Python对象
def main():try:with open('data.json','r',encoding='utf-8') as fs:yourdict=json.load(fs)print(yourdict)#youdict是一个字典或列表
正则表达式
在编写处理字符串的程序或网页时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。换句话说,正则表达式就是记录文本规则的代码。
Python提供re模块支持正则表达式的应用
函数 | 说明 |
---|---|
compile(pattern, flags=0)
|
编译正则表达式返回正则表达式对象 |
match(pattern, string, flags=0)
|
用正则表达式匹配字符串 成功返回匹配对象 否则返回None |
search(pattern, string, flags=0)
|
搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回None |
split(pattern, string, maxsplit=0, flags=0)
|
用正则表达式指定的模式分隔符拆分字符串 返回列表 |
sub(pattern, repl, string, count=0, flags=0)
|
用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数 |
fullmatch(pattern, string, flags=0)
|
match函数的完全匹配(从字符串开头到结尾)版本 |
findall(pattern, string, flags=0)
|
查找字符串所有与正则表达式匹配的模式 返回字符串的列表 |
finditer(pattern, string, flags=0)
|
查找字符串所有与正则表达式匹配的模式 返回一个迭代器 |
purge() | 清除隐式编译的正则表达式的缓存 |
re.I / re.IGNORECASE
|
忽略大小写匹配标记 |
re.M / re.MULTILINE
|
多行匹配标记 |
常用的元字符
代码 | 说明 |
---|---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
import re
def verifier(username):"""判断用户名是否有效:param username: 用户名(数字字母下划线构成 长度为6-20):return: 用户名有效返回真 无效返回假"""if 6<len(username)<20:for index in range(len(username)):if not '0'<=username[index]<='9' or 'A'<=username[index]<='Z' or \'a' <= username[index] <= 'z' or username[index]=='_':return Falsereturn Truereturn False
def main():print(verifier('1254'))print(verifier('adsds15_'))print(verifier('ghjjfff5545__-'))以前的我们都会像上面这样写,但有了正则表达式,就简单了很多如下所示username='dghfgdj_'if re.match(r'^\w{6,20}$',username):#从头开始匹配#re.search(r'^\w{6,20}$', username)#从任意位置开始匹配print('匹配成功!')else:print('匹配失败!')如果想要打印出匹配的内容可以这样写:m=re.match(r'^\w{6,20}$',usernameprint(m)if m:print(m.span())#匹配的范围print(m.group())#匹配的内容if __name__ == '__main__':main()
字符转义
如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用.和*。当然,要查找\\本身,你也得用\.
重复
代码/语法 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
def main():sentence='aabacbdaab'm=re.match(r'a.*?b',sentence)#a重复零次一次或多次print(m)
if __name__=='__main__':main()
结果:
<_sre.SRE_Match object; span=(0, 3), match='aab'>
字符类
要想查找数字,字母或数字,空白是很简单的,因为已经有了对应这些字符集合的元字符
#拆分字符
def main():sentence='You go your way, I will go mine!'mylist=re.split(r'[\s,!]',sentence)print(mylist)
if__name__=='__main__':main()
结果:
['You', 'go', 'your', 'way', '', 'I', 'will', 'go', 'mine', '']
分支条件
正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。
#替换不想看到的字符
import re
def main():sentence='我草你大爷的日你二舅'pure=re.sub('[草操艹肏日干]|fuck|shit]|fuck|shit','*',sentence,flags=re.IGNORECASE)print(pure)
结果:
我*你大爷的*你二舅
分组
用小括号来指定子表达式(也叫做分组),然后就可以指定这个子表达式的重复次数了,也可以对子表达式进行其它一些操作。
#找出字符串中数字字串,并求平均
import re
from re import findall,sub
def foo(m):val=m.group('fool')print(val)def main():sentence='656ghshgf556hsf55hsdh'pattern=re.findall(r'\d+',sentence)print(pattern)my_list=list(map(int,pattern))print(sum(my_list) / len(my_list))#建了两个分组并分别命名,这样有利于函数用哪个分组,对其进行操作print(sub(r'(?P<fool>\d+)(?P<du>[hg])',foo,sentence))#第一个分组取用数字字串,第二个分组判断数字后是不是以h或g结尾,如果是,就用‘’替代if __name__ == '__main__':main()
结果:
['656', '556', '55']
422.3333333333333
656
556
55
hshgfsfsdh
反义
有时需要查找不属于某个能简单定义的字符类的字符。比如想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义:
代码/语法 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^X] | 匹配除了x以外的任意字符 |
[^aeiou ]
|
匹配除了aeiou这几个字母以外的任意字符 |
反向引用
分类 | 代码/语法 | 说明 |
---|---|---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
(?< name >exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name’exp) | |
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号 | |
零宽断言 | (?=exp) | 匹配exp前面的位置 |
(?<=exp) | 匹配exp后面的位置 | |
(?!exp) | 匹配后面跟的不是exp的位置 | |
(?< !exp) | 匹配前面不是exp的位置 | |
注释 | (?#comment) | 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
import re
def main():# 创建正则表达式对象 使用了前瞻和回顾来保证手机号前后不应该出现数字pattern = re.compile(r'(?<=\D)1[34578]\d{9}(?=\D)')sentence = '''我的手机号是14588997755不是13245674578'''# 查找所有匹配并保存到一个列表中mylist = re.findall(pattern, sentence)print(mylist)# 通过迭代器取出匹配对象并获得匹配的内容for temp in pattern.finditer(sentence):print(temp.group())# 通过search函数指定搜索位置找出所有匹配m = pattern.search(sentence)while m:print(m.group())m = pattern.search(sentence, m.end())if __name__ == '__main__':main()
结果:
['14588997755']
<_sre.SRE_Match object; span=(6, 17), match='14588997755'>
14588997755
(6, 17)
14588997755
多重继承
除了从一个父类继承外,Python允许从多个父类继承。
class Father(object):def __init__(self, name):self._name = namedef drink(self):print(self._name + '正在喝酒')def gamble(self):print(self._name + '正在喝饮料')class Monk(object):def __init__(self, nickname):self._nickname = nicknamedef eat_vegetable(self):print(self._nickname + '正在吃斋')def chant(self):print(self._nickname + '正在念经')class Musician(object):def __init__(self, art_name):self._art_name = art_namedef paino(self):print(self._art_name + '正在弹钢琴')def drink(self):print(self._art_name + '正在喝润喉茶')class Son( Father, Monk,Musician):def __init__(self, name, nickname, art_name):Father.__init__(self,name)Monk.__init__(self,nickname)Musician.__init__(self,art_name)
#儿子类继承父类,音乐家类,和尚类的属性,在传参的 位置非常重要在Musician类中也含有drink方法,但是先传递了Father方法 所以在主函数中输出的是 Father类的drink的方法def main():son = Son('王大锤', '玄清', '贝多芬')son.drink()son.gamble()son.eat_vegetable()Musician.drink(son)if __name__ == '__main__':main()
结果:
王大锤正在喝酒
王大锤正在喝饮料
玄清正在吃斋
贝多芬正在喝润喉茶
在多重继承中,子类可重写父类中的方法
from abc import ABCMeta, abstractmethodclass Father(object):def __init__(self, name):self._name = namedef drink(self):print(self._name + '正在喝酒')def gamble(self):print(self._name + '正在打牌')class Monk(object, metaclass=ABCMeta):@abstractmethoddef eat_vegetable(self):passdef chant(self):passclass Musician(object, metaclass=ABCMeta):@abstractmethoddef paino(self):passdef drink(self):pass#子类重写父类的方法
class Son(Father, Monk, Musician):def __init__(self, name, nickname, art_name):Father.__init__(self, name)self._nickname = nicknameself._art_name = art_namedef eat_vegetable(self):print(self._nickname + '正在吃斋')def chant(self):print(self._nickname + '正在念经')def paino(self):print(self._art_name + '正在弹琴')def drink(self):print(self._art_name + '正在喝白开水')def main():son = Son('王大锤', '玄清', '贝多芬')son.drink()son.gamble()son.eat_vegetable()if __name__ == '__main__':main()
结果:
贝多芬正在喝白开水
王大锤正在打牌
玄清正在吃斋
多线程
如果一个任务执行的时间很长 可以把它分为多个任务 启用多线程 缩短执行时间
改善用户体验 让用户有更好的体验。一个进程可以划分为多个线程 线城是进程的执行单元, 也是操作系统分配CPU的基本单元。
创建线程的方式
直接创建Thread对象并通过T爱人和他参数指定线程启动后要执行的任务
继承Thraed自定义线程 通过重写run方法指定线程启动后执行的任务
from threading import Thread
class PrintThread(Thread):def __init__(self, string, count):super().__init__()self._string = stringself._count = countdef run(self):for _ in range(self._count):print(self._string, end='', flush=True)def main():PrintThread('Ping', 10000).start()PrintThread('Pomg', 20000).start()if __name__ == '__main__':main()
多线程类似于同时执行多个不同程序,多线程运行有如下优点:
- 使用线程可以把占据长时间的程序中的任务放到后台去处理。
- 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
- 程序的运行速度可能加快
- 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存。
- 线程可以被抢占(中断)。
- 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) – 这就是线程的退让。
守护线程
守护线程-不值得保留的线程-其它线程都执行完毕 守护线程结束。
daemon=Ture-将线程设置为守护线程。
```用矩形代替小车,定义一个类,用线程将五两小车以不同的速度,从一端移动到另外另外一端```
import pygame
from random import randint
from threading import Thread
from time import sleep
class Color(object):#定义全局常量 颜色Black = (0, 0, 0)White = (225, 225, 225)Gray = (242, 242, 242)#静态方法 随机颜色@staticmethoddef random_color():r = randint(0, 225)g = randint(0, 255)b = randint(0, 255)return (r,g,b)class Car(object):#定义小车的构造器,传入小车的坐标以及颜色def __init__(self, x, y, color):self._x = xself._y = yself._color = color#小车以不同的速度移动起来 def move(self):if self._x +80<950:self._x += randint(1, 10)#画小车def draw(self, screen):pygame.draw.rect(screen, self._color,(self._x, self._y, 80, 40), 0)def main():class BackgroundTask(Thread):def run(self):#画屏幕以及边界while True:screen.fill(Color.Gray)pygame.draw.line(screen, Color.Black, (130, 0), (130, 600), 4)pygame.draw.line(screen, Color.Black, (950, 0), (950, 600), 4)for car in cars:car.draw(screen)pygame.display.flip()sleep(0.05)for car in cars:car.move()cars = []#小车列表 放入五个小车,并定义小车的起点位置与颜色for index in range(5):temp = Car(50, 50+index * 120, Color.random_color())cars.append(temp)pygame.init()screen = pygame.display.set_mode([1000, 600])#启用守护线程 当主函数运行结束时线程也结束BackgroundTask(daemon=True).start()running = Truewhile running:#判断游戏界面是否QUITfor event in pygame.event.get():if event.type == pygame.QUIT:running = Falsepygame.quit()if __name__ == '__main__':main()
线程保护
当多个线程访问一个资源 就有可能因为竞争资源导致资源错误,被多个线程访问的资源我们通常称为临界资源 访问临界资源时需要保护。
import time
from threading import Thread,Lock
class Account(object):def __init__(self):self._balance = 0self._lock=Lock()#?定义存钱行为并进行保护def deposit(self, money):if money > 0:#当余额大于0时,启用保护self._lock.acquire()try: new_balance = self._balance + money#存钱需要一定的时间,避免多线程运行会出错,我们可用time来进行定义time.sleep(0.01)self._balance = new_balancefinally:#释放保户self._lock.release()@propertydef balance(self):return self._balanceclass AddMoneyTheady(Thread):#构造账户线程def __init__(self, account):super().__init__()self._account = account#调用存钱方法,并定义每次存一块钱def run(self):self._account.deposit(1)def main():account = Account()#定义一个线程列表tlist = []for _ in range(100):#存100次,并构造线程对象t = AddMoneyTheady(account)#将线程加入到线程列表中tlist.append(t)#启动线程t.start()for t in tlist:#当当前线程结束执行t.join()#打印余额print('账户余额:%d' % account.balance)if __name__ == '__main__':main()
多进程
进程 操作系统分配内存基本单位 进程之间的内存是相互隔离的, 如果要进行通信通过Ipc管道。由于Python是跨平台的,自然也提供一个跨平台的多进程支持。multiprocessing
模块就是跨平台版本的多进程模式。multiprocessing
模块提供了一个Process
来代表一个进程对象。如果多个任务之间没有任何的联系(独立的子任务)而且希望利用CPU的多核特性,推荐使用多进程。
import subprocess
#def main():#subprocess.call('calc')启用计算器#subprocess.call('notepad')启用记事本from multiprocessing import Process
import time,os
def output():print(os.getpid())while True:print('Pong',end='',flush=True)time.sleep(0.001)def main():Process(target=output).start()while True:print('Ping',end='',flush=True)time.sleep(0.001)
if __name__ == '__main__':main()
def main():Process(target=output).start()while True:print('Ping',end='',flush=True)time.sleep(0.001)if __name__ == '__main__':main()
用进程和线程分别启用下载任务
from threading import Thread
import randomdef download(filename):print('开始下载%s...' % filename)#文件下载的时间delay = random.randint(5, 15)time.sleep(delay)print('%s下载完成,用时%d秒' % (filename, delay))
#线程
class Download(Thread):def __init__(self,filename):super().__init__()self._filename=filename#钩子函数hook/回调函数callbackdef run(self):#下载文件download(self._filename)
def main():start = time.time()t1 = Download('python.pdf')t1.start()t2 =Download('追光者.MP4')t2.start()#join()等待线程结束执行t1.join()t2.join()end = time.time()#计算下载任无从开始到结束的时间print('总共耗时%f秒' % (end - start))#进程
def main():start = time.time()#直接调用进程并调用download直接开始下载任务p1 = Process(target=download, args=('python.pdf',))p1.start()p2 = Process(target=download, args=('追光者.MP4',))p2.start()p1.join()p2.join()end = time.time()print('总共耗时%f秒' % (end - start))if __name__ == '__main__':main()
网络编程
我们可以利用网络编程在客户端与服务器之间进行传递消息。Socket模块可进行网络编程
语法:
socket.socket([family[, type[, proto]]])
参数:
family: 套接字家族可以使AF_UNIX或者AF_INET
type: 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAM或SOCK_DGRAM
protocol: 一般不填默认为0.
函数 | 描述 |
---|---|
服务器端套接字 | |
s.bind() | 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址。 |
s.listen() | 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了。 |
s.accept() | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 |
客户端套接字 | |
s.connect() | 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 |
s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
公共用途的套接字函数 | |
s.recv() | 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略。 |
s.send() | 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。 |
s.sendall() | 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 |
s.recvfrom() | 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 |
s.sendto() | 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。 |
s.close() | 关闭套接字 |
s.getpeername() | 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 |
s.getsockname() | 返回套接字自己的地址。通常是一个元组(ipaddr,port) |
s.setsockopt(level,optname,value) | 设置给定套接字选项的值。 |
s.getsockopt(level,optname[.buflen]) | 返回套接字选项的值。 |
s.settimeout(timeout) | 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) |
s.gettimeout() | 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None。 |
s.fileno() | 返回套接字的文件描述符。 |
s.setblocking(flag) | 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常。 |
s.makefile() | 创建一个与该套接字相关连的文件 |
构建服务器与客户端 之间可以传送消息(一收一发)
#服务器
from socket import socket, AF_INET, SOCK_STREAM
import time
import datetimedef main():#创建一个基于tcp的服务器的套接字对象#我们做的是应用级的产品或服务所以可以利用现有的传输服务来实现数据传输server = socket()#绑定Ip地址(网络上的主机的身份标识)和端口(用来区分不同服务的IP地址的拓展)server.bind(('10.7.189.81', 6789)) # 本机#开始监听客户端的连接server.listen(512) #512为队列大小 是2的次幂print('服务器已经启动正在监听...')while True:#通过accept方法 接收客户端的连接#accept方法是一个阻塞式的方法 如果没有客户端连上来#那么accept方法就会让代码阻塞 直到有客户端连接上#accept 方法返回一个元祖 元祖中的第一个值是代表客户端的对象#元祖中的第二个值又是一个元祖 其中有客户端的Ip地址和端口client,addr = server.accept()print(addr,'连接成功')client.send(str(datetime.datetime.now()).encode('utf-8'))#time.localtime(time.time())client.close()
#客户端from socket import socket
def main():client=socket()#连接服务器client.connect(('10.7.189.81',6789))#接收服务器的消息data=client.recv(512)print(type(data))#对接收的消息进行编码print(data.decode('utf-8'))
if __name__ == '__main__':main()
客户端与服务器之间收发消息,客户端发,服务器收,一致保持此状态(一收一发)
# 客户端
class MyTheade(Thread):#构造线程def __init__(self, news):super().__init__()self.news = newsdef main():client = socket()#联接服务器client.connect(('10.7.189.81', 6789))#一直保持收接消息的状态while True:#输入传入的消息news = input('??入:')#启用线程MyTheade(news).start()#发送消息 并进行编码client.send(str(news).encode('utf-8'))#接收服务器端的消息 并编码data = client.recv(512)print(data.decode('utf-8'))#服务器端
from socket import socket
from threading import Thread
class MyTheade(Thread):def __init__(self,new):super().__init__()self.new=new
def main():server = socket()#绑定服务器与端口server.bind(('10.7.189.81 ', 6789))#监听客户端server.listen(512)print('服务器已经启动正在监听...')#接收并显示客户端的ip,与连接状况client, addr = server.accept()print(addr, '连接成功')while True:#接收客户端发送的消息并进行编码并输出data = client.recv(512)print(data.decode('utf-8'))#回复客户端回消息,并进行编码new=input('你要发送的消息?:')#启动线程MyTheade(new).start()client.send(new.encode('utf-8'))
if __name__ == '__main__':main()
建立聊天室 并显示所有的聊天信息
# 服务器
from socket import socket
from threading import Threaddef main():class ClientHandler(Thread):#构造线程?,传入客户def __init__(self, client):super().__init__()self._client = clientdef run(self):while True:#有风险的语句 放在try里try:#接收客户端消息data = self._client.recv(1024)#如果收到byebye 将这个客户移除,并关闭她的端口if data.decode('utf-8') == 'byebye':clients.remove(self._client)self._client.close()break#将每个客户发送消息到服务器for client in clients:client.send(data)#将异常的客户移除except Exception as e:print(e)clients.remove(self._client)breakserver = socket()# 命令行参数 sys.argv#绑定服吴器与端口server.bind(('10.7.189.81', 12345))#监听客户端server.listen(512)#定义客户列表clients = []while True:#接收当前客户curr_client, addr = server.accept()#将客户放入客户列表中clients.append(curr_client)#启用线程,开始处理目前客户ClientHandler(curr_client).start()
#客户端
from socket import socket
from threading import Threaddef main():class RefreshScreenThread(Thread):#构造刷新界面线程def __init__(self, client):super().__init__()self._client = clientdef run(self):while running:#接收所有客户消息并进行编码data = self._client.recv(512)print(data.decode('utf-8'))#客户昵称nickname = input('请输入你的昵称:')#定义套接字myclient = socket()#连接服务器与端口myclient.connect(('10.7.189.81', 12345))running = True#启用刷新界面消息功能RefreshScreenThread(myclient).start()while running:#定义你要说的信息content = input('请发言:')#如果输入的是byebye,进行编码,发送到服务器,服务器会关闭当前的端口,客户端将终止循环if content=='byebye':myclient.send(content.encode('utf-8'))running=Falseelse:#将你的逆臣与消息进行编码发送到服务器msg = nickname+':' + contentmyclient.send(msg.encode('utf-8'))if __name__ == '__main__':main()
图片编程
我们可以利用文件的读写来给服务器或者客户端进行发送图片
#客户端
from socket import socket, SOCK_STREAM
from time import sleepdef main():sender = socket(type=SOCK_STREAM)#打开文件with open('1.jpg', 'rb') as f:#读取文件data = f.read()#计算文件的长度datalen = len(data)total = 0while total < datalen:#将文件切片发送到服务器sender.sendto(data[total:total + 1024], address=('10.7.189.81', 6888))total += 1024sleep(0.001)
if __name__ == '__main__':main()
#服务器
from socket import socket, SOCK_DGRAM
def main():receiver = socket(type=SOCK_DGRAM)#绑定服务器与端口receiver.bind(('10.7.189.81', 6888))data = bytes()while True:#接收客户端发送的切片信息seg, addr = receiver.recvfrom(1024)data += seg#判断照片的大小if len(data) >=137827:break#打开文件并写入文件with open('2.jpg', 'wb') as f:f.write(data)print('图片已接收.')
邮件发送
我们也可以利用网络编程来发送邮件,Python中有MIMEText
函数,可利用这个函数进行发送邮件
发送普通邮件
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from smtplib import SMTP_SSL#发送内容content = """我跟你说着玩的今晚出去玩,明天开会早点睡"""# MIME-Multipurpose Internet Maill#输入的内容为普通格式 编码utf-8message = MIMEText(content, 'plain', 'utf-8')#发送邮件的主题message['Subject'] = '今天请你吃饭'#第一邮箱发信人邮箱,第二个为收件人邮箱sender.sendmail('1435246152@qq.com', '1013622764@qq.com', message.as_string())print('发送成功!')
发送附件
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from smtplib import SMTP_SSLdef main():# 附件sender = SMTP_SSL('smtp.qq.com', 465)sender.login('1435246152@qq.com', 'trbytuakgrjlhdge')message = MIMEMultipart()message['Subject'] = '请查收文件的数据'text_msg = MIMEText('附件中有关本月关键数据晴查收', 'plain', 'utf-8')message.attach(text_msg)att2 = MIMEText(open('1.xlsx', 'rb').read(), 'base64', 'utf-8')att2['Content-Type'] = 'application/vnd.ms-excel'att2['Content-Type'] = 'attachment;filename==foo.xlsx'message.attach(text_msg)sender.sendmail('1435246152@qq.com', '1013622764@qq.com', message.as_string())print('发送成功!')
Python文件的读写、正则表达式的运用、多线程与多进程、网络编程相关推荐
- python的多线程和多进程网络编程
二十八.python的多线程和多进程网络编程 线程和进程关系: 进程是具有独立功能的程序,进程是系统进行资源分配和调度的一个独立单位 线程是进程的一个实体,是cpu调度的基本单位,它是比进程更小的能独 ...
- Python可以这样学(第三季:多线程与多进程编程)-董付国-专题视频课程
Python可以这样学(第三季:多线程与多进程编程)-7527人已学习 课程介绍 董付国老师系列教材<Python程序设计(第2版)>(ISBN:9787302436515 ...
- Python文件的读写操作
使用Python编程时,经常会遇到读写文件的操作.对于读写文件的各种模式(如阅读.写入.追加等)有时真的会迷惑人,以及搞不清open.read.readline.readlines.write.wri ...
- Python文件的读写以及操作excel
文件的读写操作 使用open函数打开文件 f = open(文件名,'读写操作') f.close() # 例如 open('root.txt','w') 2.常见的操作有 操作模式 具体含义 'r' ...
- Python 文件的读写模式
一, r :读取模式(默认值) w:写入模式 x:独占写入模式 a:附加模式 b:二进制模式 t:文本模式(默认值,与其他模式结合使用) +:读写模式(与其他模式结合使用) r+: 打开 ...
- Python文件的读写及常用文件的打开方式
编码格式 常见的编码格式 Python的解释器使用的是Unicode(内存) .py文件在磁盘上使用UTF-8(外存) 更改编码格式 一般形式为在程序开头写 # coding:编码格式.# codin ...
- python异步多线程框架_Python网络编程中的服务器架构(负载均衡、单线程、多线程和同步、异步等)。...
这篇文章主要介绍服务器架构. 网络服务需要面对两个挑战.第一个问题是核心挑战,要编写出能够正确处理请求并构造合适响应的代码. 第二个挑战是如何将网络代码部署到随系统自动启动的Windows服务或者是U ...
- Python学习,gevent协程,多线程,多进程demo
协程,线程,进程,多线程,多进程,线程池,本渣渣是彻底蒙蔽了,不过干就是了,二话不说写(抄)代码就是了,抄多了就明了了,说错了,写多了就会了! 关于gevent Python通过yield提供了对协程 ...
- 段鹏飞java_面向对象与多线程综合实验-网络编程
教师:段鹏飞 实验5-实验目的 了解Java网络编程基础知识;掌握java.net包中关于网络的基本类及其属性和方法;掌握基于Socket的客户和服务器编程方法. 实验内容(必做) 编写程序,将前面课 ...
最新文章
- python哪一版好用-Python 可视化工具库哪款最好用?哪款最不好用?
- 算法积分0042算法笔记——【随机化算法】计算π值和计算定积分
- 输入一个字母,转大小写
- HTML cite元素
- java多状态机_一个java状态机样例的代码
- 198. house robber 题解
- java字符串的替换replace、replaceAll、replaceFirst的区别详解
- 如何将ffmpeg在windows编译和使用
- OC-NSFileManager
- 金融破段子 | 如果早知赚钱概率只有8%,你会不会改变投资策略
- windows10完全卸载windows自带的skype
- ppt文件怎么压缩,ppt压缩的办法步骤
- CK11N改标准价格
- 移动App Store测试的“七宗罪”
- EL表达式基础语法总结
- rabbit ack机制
- [raspberry]树莓派无线鼠标延迟问题
- 程序员求职之道(《程序员面试笔试宝典》)之面试笔试技巧?
- NTRIP/nbsp;SUPL
- VirtualBox - 自动调整屏幕大小,设置虚机自适应显示器