后面学习了线程、协成和异步,它们的框架都是基于socket的协议,基本原理都是一样的,现在把这几个模块重温一下,尽量掌握这些知识更全面一些。

动态导入模块,知道知道模块名,可以像反射一样,使用字符串来导入模块。

mod = __import__("mulit")
print(mod)
mod.f("alex")
运行结果如下:
<module 'mulit' from '/home/zhuzhu/day10/mulit.py'>
called from child process function f
module name: mulit
parent process: 2092
process id: 3613 hello alex

上面就实现了动态导入模块的方法,动态导入模块。官方建议使用importlib模块实现模块字符串的动态导入,如下:

import importlib

mulit = importlib.import_module("importy.mulit")

print(mulit)
运行结果如下:
<module 'importy.mulit' from '/home/zhuzhu/day10/importy/mulit.py'>

上面代码就实现了动态导入importy包下的mulit模块,这样,我们就能够实现,只知道模块的字符串名字,动态的导入模块。

    断言:

'''断言'''

name = "alex"
print(name)
assert type(name) is int
print("断言是如何算的") '''断言:如果是正确的,程序继续执行下面;如果是错误的,程序就执行错误。报错AssertionError,直接停住不执行,后面不管对错'''
#断言的作用:就是没有循环的中断程序。执行错误。

断言这个也在后期用到,即终端操作的时候。

socket:封装协议底层,现在所有的底层都是基于socket来实现的。网络协议

    conn,addr = socket.accept()

一定要记住,socket.accept()是接收了一个链接和一个地址,conn去实现链接,conn.recv()来接收,因为conn是链接。

recv(1024)  官方建议接收数据不能超过8192(8K);

conn.recv(1024)和conn.send()是实现数据的收发,数据一定要有收发配对,防止粘包。并且只能收发二进制字符串格式。要转换为二进制才能进行发送。

不能接收和发送空的数据,recv()不能接收空的消息,接收空的消息就会卡主。微信、QQ我们知道,都不允许发送空的消息。

下面使用类创建了一对sockek客户端和socket服务器端,实现数据的收发,如下所示:

    服务器端:

import socket

class MyServer(object):
'''创建服务器端'''
def __init__(self):
self.server = socket.socket() def bind(self,ip,port):
'''绑定连接'''
self.server.bind((ip,port))
self.server.listen() def interactive(self):
while True:
'''实现接收终止,但是服务器端没有断开,等待新的链接进来'''
conn, addr = self.server.accept() # 开始准备接收数据
while True:
data = conn.recv()
if len(data) == :
print("客户端断开了,接收数据不能为空!!!")
break
conn.send("接收到了数据".encode("utf-8"))
print(data.decode("utf-8")) if __name__ == "__main__":
try:
server = MyServer()
server.bind("localhost",)
server.interactive()
except KeyboardInterrupt as e:
print("服务器已经断开了!!!",e)

    客户端:

import socket

class Myclient(object):
'''建立客户端'''
def __init__(self):
self.client = socket.socket() def communicate(self,ip,port):
self.client.connect((ip,port)) #建立链接 def interactive(self):
'''实现交互'''
while True:
mess = input("请输入您要交互的内容>>:").strip()
if not mess:
print("消息不能为空!!")
continue
self.client.send(mess.encode("utf-8"))
data = self.client.recv()
print(data.decode("utf-8")) if __name__ == "__main__":
try:
client = Myclient()
client.communicate("localhost",)
client.interactive()
except KeyboardInterrupt as e:
print("客户端断开了!!!")

上面就是客户端和服务器端,首先要启动的是服务器端,然后在客户端进行收发数据,从而实现数据的交换,但是不能如何实现,单纯的socket,不能实现多用户交互,只有等一个用户交互完成之后,才能让另一个用户实现交互。

上面交互如下所示:

    客户端发送:

请输入您要交互的内容>>:客户端不能发送空的消息
接收到了数据
请输入您要交互的内容>>:服务器端也不能发送空的消息
接收到了数据
请输入您要交互的内容>>:客户端和服务器端交互是一对的
接收到了数据
请输入您要交互的内容>>:send和recv()
接收到了数据
请输入您要交互的内容>>:如果主动断开会报错,所以加入了一个异常处理
接收到了数据
请输入您要交互的内容>>:服务器端加入了两层循环,主要目的是在内存循环停止接收数据之后,链接还存在,并没有实现断开
接收到了数据
请输入您要交互的内容>>:客户端断开了!!!

    服务器端接收:

客户端不能发送空的消息
服务器端也不能发送空的消息
客户端和服务器端交互是一对的
send和recv()
如果主动断开会报错,所以加入了一个异常处理
服务器端加入了两层循环,主要目的是在内存循环停止接收数据之后,链接还存在,并没有实现断开
客户端断开了,接收数据不能为空!!!
服务器已经断开了!!!

上面就是简单的数据收发,要知道,线程,协成,进程都是基于socket实现的,而且很多方法都是类似的。

服务器端有两层循环,外层循环是用来不断接收新的链接,内存循环是用来不停接收用户数据,因为如果接收中断,当前链接是要终端的。只能等待新的链接进来,实现数据的交互。

上面服务器代码中,data = conn.recv(1024),接收的数据大小是1024(1K)个字节,如果超过1K字节会出现什么情况,下面来看一下:

  服务器接收:

正常传输数据没有问题
当传输数据超过1024的时候,会出现怎样的错误
My father was a self-taught mandolin player. He was one of the best string instrument players in our town. He could not read music, but if he heard a tune a few times, he could play it. When he was younger, he was a member of a small country music band. They would play at local dances and on a few occasions would play for the local radio station. He often told us how he had auditioned and earned a position in a band that featured Patsy Cline as their lead singer. He told the family that after he was hired he never went back. Dad was a very religious man. He stated that there was a lot of drinking and cursing the day of his audition and he did not want to be around that type of environment.Occasionally, Dad would get out his mandolin and play for the family. We three children: Trisha, Monte and I, George Jr., would often sing along. Songs such as the Tennessee Waltz, Harbor Lights and around Christmas time, the well-known rendition of Silver Bells. "Silver Bells, Silver Bells, its Christmas time in the city" w
Traceback (most recent call last):
File "/home/zhuzhu/第八天/socket_server.py", line , in <module>
server.interactive()
File "/home/zhuzhu/第八天/socket_server.py", line , in interactive
length = int(length.decode("utf-8")) #接收数据的大小
ValueError: invalid literal for int() with base : 'ould ring throughout the house. One of Dad\'s favorite hymns was "The Old Rugged Cross". We learned the words to the hymn when we were very young, and would sing it with Dad when he would play and si

可以看出当传输超过1024字节的时候报错了,这个有时候能接收到报错,有时候接收不到报错,因此尽量不要发超过1024字节的消息,要想发,只能修改服务器的代码,让服务器分段接收数据,如下:

import socket

class MyServer(object):
'''创建服务器端'''
def __init__(self):
self.server = socket.socket() def bind(self,ip,port):
'''绑定连接'''
self.server.bind((ip,port))
self.server.listen() def interactive(self):
while True:
'''实现接收终止,但是服务器端没有断开,等待新的链接进来'''
conn, addr = self.server.accept() # 开始准备接收数据
while True:
length = conn.recv()
if len(length) == :
print("客户端断开了!!!")
break
length = int(length.decode("utf-8")) #接收数据的大小
conn.send("数据的长度接收到了!!!".encode("utf-8"))
receive_size =
received_data = b""
while receive_size < length:
data = conn.recv()
receive_size += len(data)
received_data +=
data
conn.send("接收到了数据".encode("utf-8"))
print(received_data.decode("utf-8"),length) if __name__ == "__main__":
try:
server = MyServer()
server.bind("localhost",)
server.interactive()
except KeyboardInterrupt as e:
print("服务器已经断开了!!!",e)

上述代码中,首先服务器接收的不是消息,而是消息的长度,然后才开始接收,通过判断,只要接收的长度小于消息的长度,就一直接收,并且拼接到一起,这样就能接收超过1024字节,并且不会报错,如下:

    服务器端接收:

现在修改了服务器
让服务器接收超过1024时,分批接收数据,然后拼接到一起
西汉和东汉仍置南阳郡,辖境相当于河南熊耳山以南和湖北大湖 山以北,南阳经济文化的发展达到历史上的鼎盛时期。西汉时,南阳水利与关中郑国渠、成都都江堰齐名,并称全国三大灌区。全国设工官的9个地区和设铁官的46个地区之一。东汉 时,光武帝刘秀起兵南阳,成就帝业,南阳被称为“帝乡”。诸葛亮躬耕南阳卧龙岗,刘备三顾茅庐,诸葛亮提出“三分天下”之计。太守杜诗修治坡池,广拓田土,全郡可灌农田4万顷 ,这时的冶铁用水排, 水力鼓风机鼓风,大大提高了冶铁效率,特别是采用球墨铸铁,提 高了冶铁工艺水平,这一技术的使用比欧州早1000多年。当时南阳郡人口240万,为全国各 郡之冠。郡城周长36公里,比1990年市区面积还大。汉代南阳人才辈出,灿若繁星。不仅刘秀的28个开国元勋大多出自南阳,还涌现出张衡、张仲景闻名世界的伟大科学家和医学家。汉代达官贵人死后流行厚葬,南阳出土众多的画像石和画像砖,是一部“绣像汉代史”,成为中华民族文化艺术宝库中一朵绚丽多彩的奇葩。三国时期:南阳为魏国所有,隶属荆州。晋代:南阳曾为南阳国,辖十四县,都宛。隋朝:(607年)先将郡改州,后又将州改郡,今南阳市辖南阳郡、淯阳郡、淅阳郡、淮安郡(包括平氏、桐柏二县),义阳郡的淮源县、舂陵郡的湖阳县等都在今南阳市内。唐朝,天下设为十道,南阳属山南道管辖。自唐高祖李渊至玄宗李隆基90年间,南阳先后设置纯州、郦州、淅州、北澧州、宛州、淯州、显州、湖州、新州、鲁州和仙州等。玄宗天宝元年(742年)改州为郡,邓州称南阳郡,唐州称淮安郡。肃宗乾 元元年(758年)又改郡称州,县加以合并,今南阳市有泌州淮安郡和邓州南阳郡。经过贞观 、开元之治,南阳农业兴旺,工商业繁荣。李白在《南都行》中说:“清歌遏流云,艳舞有 余闲,邀游盛宛洛,冠盖随风还。”宋朝:南阳归京西南路管辖,南阳叫武胜军,设唐、邓 二州,州下设县,邓州辖穰、南阳、内乡、淅川、顺阳五县。唐州辖有泌阳、湖阳、桐柏、方城等县。元朝:将原南阳郡改为南阳府。属河南江北行中书省。辖五州,其三在今市内; 南阳府自领镇平、南阳二县;邓州领内乡、顺阳、淅川、新野、栾川五县;唐州领泌阳、湖阳、桐柏、方城等县。其他二州辖临汝、伊川、郏县、宝丰、鲁山、叶县、舞阳、卢氏、栾川等县。其间曾将淅川、顺阳合并到内乡。明朝初年,南阳是朱元璋第二十三子唐王朱柽的封地,永乐年间在南阳城内建造了规模宏大的唐王府,成化年间又建造9座郡王府,南阳城 内皇亲贵胄,车水马龙,商业随之活跃,山、陕、江、浙、川、鄂客商纷到沓来,各种商务会馆、公馆在各地兴起,粮食、棉花、生丝、烟草、绸缎、油料、皮毛、木材、药材、铜器、铁器等大量涌入市场,并行销全国各地。当时的南阳可谓百业俱兴,建筑、园林、绘画、雕塑、书法等方面都有新的发展。清朝康熙年间,建筑业尤为发达,武侯、山陕会馆等古建筑巍巍壮观,富丽堂皇,南阳是北京通往湖广和云贵川的交通要道,陆路驿道与水路码头相接,有“南船北马”之称。山、陕、江、浙商贾云之集,工商业兴旺,南阳成了豫西南的经济中心。光绪十年,镇平开始生产丝绸,并远销欧洲及东南亚各国。民国时期:河南设十一个行政区,南阳为第六行政区,辖十三个县:南阳县、南召、唐河、镇平、方城、邓县、内乡、桐柏、新野、淅川、泌阳、叶县、舞阳县。中华人民共和国时期:(1949年)成立后,南阳行政公署划走叶县、舞阳。析出西峡、南阳市,仍辖十三个县市,即南阳市、南召、方城、泌阳、唐河、新野、桐柏

上面,服务器端接收了超过1024字节的数据,但是一点问题都没有。

    ftp server发送文件给客户端的步骤:

1、读取文件名;

  2、检测文件是否存在;

  3、打开文件;

  4、检测文件大小;

  5、发送文件大小和md5给客户端;   md5验证

  6、等待客户端确认;

  7、开始边读边发数据;

使用socket实现文件的传输,下面的例子是从服务器端下载文件,具体代码如下:

    服务器端:

import socket,os,json,hashlib

class MyServer(object):
'''创建server实例'''
def __init__(self):
self.server = socket.socket() def bind(self,ip,port):
self.server.bind((ip,port))
self.server.listen() def interactive(self):
'''实现交互'''
while True:
conn,addr = self.server.accept() #循环实现链接不断开,客户端断开不影响
while True:
filename = conn.recv().decode("utf-8") #接收文件名
if len(filename) == : #判断客户端是否断开,客户端不可能发送空的,接收空,就是客户端断开了
print("客户端断开了!!!")
break
if os.path.isfile(filename): #判断客户端文件是否存在
'''文件名存在'''
conn.send("".encode("utf-8"))
'''文件存在,准备发送文件,首先告知客户端文件名和文件大小'''
filesize = os.stat(filename).st_size
file_mess = {"filesize":filesize}
conn.recv()
conn.send(json.dumps(file_mess).encode("utf-8")) #发送文件的大小指令
conn.recv()
'''下面开始发送文件信息'''
m = hashlib.md5()
with open(filename,"rb") as f:
for line in f:
m.update(line)
conn.send(line) #逐行发送文件
'''文件发送完毕之后,发送md5值'''
mess = m.hexdigest()
conn.send(mess.encode("utf-8"))
else:
'''文件不存在'''
conn.send("".encode("utf-8"))
conn.recv() if __name__ == "__main__":
try:
server = MyServer()
server.bind("localhost",)
server.interactive()
except KeyboardInterrupt as e:
print("服务器端断开了!!!")

服务器里面,交互有两层循环,外层循环是保持链接一直存在,防止客户端关闭之后,服务器端也断开,正常不循环链接,客户端断开之后,服务端也会断开的。并且要记住,如果客户端断开,conn.recv(1024)是接收空的数据,因此一定要进行判断,如果接收为空,说明是客户端断开了,因为客户端是不可能发送空给服务器的。

    客户端:

'''通过接收发送数据的大小来训话接收,如果接收完成,则退出'''
import socket,json,hashlib
class MyClient(object):
'''创建Client实例'''
def __init__(self):
self.client = socket.socket() def connect(self,ip,port):
self.client.connect((ip,port)) def interactive(self):
'''实现交互,客户端接收文件'''
while True:
filename = input("请输入您要下载的文件名>>:").strip()
if len(filename) == :
print("文件名不能为空!!!")
continue
elif filename == "q":
break
self.client.send(filename.encode("utf-8")) #发送文件名给服务器
file_exist = int(self.client.recv().decode("utf-8")) #接收客户端返回文件是否存在的指令
self.client.send("好的,收到反馈的指令!".encode("utf-8")) if file_exist:
'''文件存在'''
file_mess = json.loads(self.client.recv().decode("utf-8"))
filesize = file_mess["filesize"]
self.client.send("收到文件的信息".encode("utf-8"))
receive_size =
m = hashlib.md5()
with open(filename+"","wb") as f:
while receive_size < filesize:
if filesize - receive_size > : #确保数据完整的接收,这样就能防止粘包
size =
else:
size = filesize - receive_size
# print("最后一次接收文件大小:",size) #由于是逐行发送数据的,因此会出问题
data = self.client.recv(size)
m.update(data)
f.write(data)
receive_size += len(data) #这里判断长度,一定是len(data)不能是size,
server_md5 = self.client.recv().decode("utf-8")
print("客户端md5值",m.hexdigest())
print("服务器md5值",server_md5)
if server_md5 == m.hexdigest():
print("数据接收完毕,通过MD5验证!!!")
else:
print("对不起,您要下载的文件不存在")
continue if __name__ == "__main__":
try:
client = MyClient()
client.connect("localhost",)
client.interactive()
except KeyboardInterrupt as e:
print("客户端断开了!!!")

我们知道,为了防止粘包,我们通常使用的方法是,客户端--服务器端发送数据之后,双方要进行确认,确认对方接收到了消息,并把这个结果告知对方,这样就能防止粘包,还有上面这种情况是,告知对方发送数据的大小,然后按照数量进行接收,只要确保全部数据接收完毕,那么就一定不会造成粘包。造成粘包的原因就是,一方没有接收完毕数据,另外一方有发送数据过来,这样就造成了粘包。

上面的交互如下:

    客户端:

请输入您要下载的文件名>>:file_test
最后一次接收文件大小:
最后一次接收文件大小:
客户端md5值 576a9a93dc5377b7a204b48df224569d
服务器md5值 576a9a93dc5377b7a204b48df224569d
数据接收完毕,通过MD5验证!!!
请输入您要下载的文件名>>:file_test
最后一次接收文件大小:
最后一次接收文件大小:
客户端md5值 576a9a93dc5377b7a204b48df224569d
服务器md5值 576a9a93dc5377b7a204b48df224569d
数据接收完毕,通过MD5验证!!!
请输入您要下载的文件名>>:客户端断开了!!!

上面在客户端和服务器连接之后,客户端发送指令,交互的情况。可以看出,交互没有问题,要注意的是,判断接收长度的时候,一定要len(data),而不能指定数量,因为只要接收数量小于等于规定的值就没有问题。

day8--socket回顾的更多相关文章

  1. Python之路,Day8 - Socket编程进阶

    Python之路,Day8 - Socket编程进阶   本节内容: Socket语法及相关 SocketServer实现多并发 Socket语法及相关 socket概念 socket本质上就是在2台 ...

  2. Python之旅Day8 socket网络编程

    socket网络编程 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可.soc ...

  3. Python学习-day8 socket进阶

    还是继续socket网络编程的学习. socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None) Socket Fami ...

  4. day8 socket

    代码: 例子1:socket tcp 通讯 server端 import socketserver = socket.socket()ip_port = ("127.0.0.1", ...

  5. Day8 - Python网络编程 Socket编程

    Python之路,Day8 - Socket编程进阶   本节内容: Socket语法及相关 SocketServer实现多并发 Socket语法及相关 socket概念 socket本质上就是在2台 ...

  6. 第九章:Python の 网络编程基础(一)

    本課主題 何为TCP/IP协议 初认识什么是网络编程 网络编程中的 "粘包" 自定义 MySocket 类 本周作业 何为TCP/IP 协议 TCP/IP协议是主机接入互网以及接入 ...

  7. 【目录】Python自动化运维

    目录:Python自动化运维笔记 Python自动化运维 - day2 - 数据类型 Python自动化运维 - day3 - 函数part1 Python自动化运维 - day4 - 函数Part2 ...

  8. Update(Stage4):Spark Streaming原理_运行过程_高级特性

    Spark Streaming 导读 介绍 入门 原理 操作 Table of Contents 1. Spark Streaming 介绍 2. Spark Streaming 入门 2. 原理 3 ...

  9. 【Java】网络编程之NIO

    简单记录 慕课网-解锁网络编程之NIO的前世今生 & 一站式学习Java网络编程 全面理解BIO/NIO/AIO 内容概览 文章目录 1.[了解] NIO网络编程模型 1.1.NIO简介 1. ...

  10. Socket编程回顾,一个最简单服务器程序

    第一次接触服务器是快毕业的时候,是不是有点晚(# ̄ω ̄),这也导致工作方向一直没考虑网络编程这块,做了好多其他没啥“意思”的技术. 之前看到一篇博文提到程序猿80%都是庸才,10%是人才,10%是天才 ...

随机推荐

  1. 关于javaBean,pojo,EJB

    JavaBean是公共Java类 1.所有属性为private.2.提供默认无参构造方法.3.类属性通过getter和setter操作.4.实现serializable接口.

  2. MySQL事物(一)事务隔离级别和事物并发冲突

    数据库的操作通常为写和读,就是所说的CRUD:增加(Create).读取(Read).更新(Update)和删除(Delete).事务就是一件完整要做的事情.事务是恢复和并发控制的基本单位.事务必须始 ...

  3. readn.c

    #include <errno.h> #include <unistd.h> ssize_t readn(int fd, void *vptr, size_t n) { siz ...

  4. div背景透明内容不透明与0.5PX边框兼容设置

    1.问题:设置 border-width:0.5px;  并兼容安卓和苹果移动端.  兼容:苹果IOS的 safari 支持浮点数边框,安卓浏览器不支持,会四舍五入到1px.不同浏览器效果额不同  解 ...

  5. 矩阵NumPy

    常量: np.pi π 创建矩阵数组 import numpy as np # array=np.array([[1,2,3],[5,6,7]]) #定义一个2行3列的矩阵数组.2行=2维 # pri ...

  6. 带事件的Bootstrap模态框的使用2

    模态框中显示一些基本的数据以及触发一些基本的JS函数 <%@ page language="java" contentType="text/html; charse ...

  7. vc++调用exe获取输出信息

    目的 调用命令行程序,返回结果. 思路 把命令行结果输入到管道中,exe的输出信息都存在了strOutput这个变量里. 实现代码 CString strCmd = L"yara64.exe ...

  8. 转载-通俗理解BN(Batch Normalization)

    转自:参数优化方法 1. 深度学习流程简介 1)一次性设置(One time setup)          -激活函数(Activation functions) - 数据预处理(Data Prep ...

  9. Andrew Ng在coursera上的ML视频 知识点笔记(2)

    一.由线性回归导出逻辑回归: 二.“一对多”算法解决多分类问题: 三.“过拟合”和“欠拟合”: (1)对线性回归加入正则项: (2)对逻辑回归加入正则项: (3)加入正则项之后的正规方程:

  10. TERMIOS详解【转】

    转自:https://blog.csdn.net/guo_wangwei/article/details/1102931# TERMIOS NAME termios, tcgetattr, tcset ...