门户网站用什么程序做微信开发者平台登录
门户网站用什么程序做,微信开发者平台登录,中国企业500强2023,可信网站认证 代理商第1章 异常处理 1.1 什么是异常? 1.1.1 描述 #1 什么是异常#xff1f; # 异常是错误发生的信号#xff0c;一旦程序出错#xff0c;就会产生一个异常#xff0c;应用程序未处理该异常#xff0c; # 异常便会抛出#xff0c;程序随之终止 异常就是程序运行时发生错误的信… 第1章 异常处理 1.1 什么是异常? 1.1.1 描述 #1 什么是异常 # 异常是错误发生的信号一旦程序出错就会产生一个异常应用程序未处理该异常 # 异常便会抛出程序随之终止 异常就是程序运行时发生错误的信号在程序出现错误时则会产生一个异常若程序没有处理它则会抛出该异常程序的运行也随之终止在python中,错误触发的异常如下 1.1.2 错误分类 而错误分成两种 1.语法错误这种错误根本过不了python解释器的语法检测必须在程序执行前就改正#语法错误示范一if#语法错误示范二def test:pass#语法错误示范三class Foopass#语法错误示范四print(haha 语法错误 2.逻辑错误#TypeError:int类型不可迭代for i in 3:pass#ValueErrornuminput(: ) #输入helloint(num)#NameErroraaa#IndexErrorl[egon,aa]l[3]#KeyErrordic{name:egon}dic[age]#AttributeErrorclass Foo:passFoo.x#ZeroDivisionError:无法完成计算res11/0res21str 逻辑错误 1.2 异常的种类 在python中不同的异常可以用不同的类型python中统一了类与类型类型即类去标识一个异常标识一种错误 1.2.1 常用异常 #######################常用异常####################AttributeError 试图访问一个对象没有的树形比如foo.x但是foo没有属性xIOError 输入/输出异常基本上是无法打开文件ImportError 无法引入模块或包基本上是路径问题或名称错误IndentationError 语法错误的子类 代码没有正确对齐IndexError 下标索引超出序列边界比如当x只有三个元素却试图访问x[5]KeyError 试图访问字典里不存在的键KeyboardInterrupt CtrlC被按下NameError 使用一个还未被赋予对象的变量SyntaxError Python代码非法代码不能编译(个人认为这是语法错误写错了TypeError 传入对象类型与要求的不符合UnboundLocalError 试图访问一个还未被设置的局部变量基本上是由于另有一个同名的全局变量导致你以为正在访问它ValueError 传入一个调用者不期望的值即使值的类型是正确的 常用异常 1.2.2 更多异常 ArithmeticErrorAssertionErrorAttributeErrorBaseExceptionBufferErrorBytesWarningDeprecationWarningEnvironmentErrorEOFErrorExceptionFloatingPointErrorFutureWarningGeneratorExitImportErrorImportWarningIndentationErrorIndexErrorIOErrorKeyboardInterruptKeyErrorLookupErrorMemoryErrorNameErrorNotImplementedErrorOSErrorOverflowErrorPendingDeprecationWarningReferenceErrorRuntimeErrorRuntimeWarningStandardErrorStopIterationSyntaxErrorSyntaxWarningSystemErrorSystemExitTabErrorTypeErrorUnboundLocalErrorUnicodeDecodeErrorUnicodeEncodeErrorUnicodeErrorUnicodeTranslateErrorUnicodeWarningUserWarningValueErrorWarningZeroDivisionError 更多异常 1.2.3 常见异常类型 #2、常见异常类型#I:语法错误应该在程序运行前修正# if 1 2# print(xxxxx)#II:逻辑错误# x# l[]# l[10000] #IndexError# class Foo:# pass# Foo.x #AttributeError:# k{x:1}# k[y] #KeyError# 1/0 #ZeroDivisionError# for i in 3: #TypeError:# pass# ageinput(: ) #ValueError# ageint(age) 常见异常类型 1.3 异常处理 1.3.1 异常处理描述 为了保证程序的健壮性与容错性即在遇到错误时程序不会崩溃我们需要对异常进行处理 如果错误发生的条件是可预知的我们需要用if进行处理在错误发生之前进行预防 AGE10while True:ageinput(: ).strip()if age.isdigit(): #只有在age为字符串形式的整数时,下列代码才不会出错,该条件是可预知的
ageint(age)if age AGE:print(you got it)break View Code 如果错误发生的条件是不可预知的则需要用到try...except在错误发生之后进行处理 #基本语法为try:被检测的代码块except 异常类型try中一旦检测到异常就执行这个位置的逻辑#举例try:fopen(a.txt)g(line.strip() for line in f)print(next(g))print(next(g))print(next(g))print(next(g))print(next(g))except StopIteration:f.close() View Code 1.3.2 异常分类使用 #1 异常类只能用来处理指定的异常情况如果非指定异常则无法处理。s1 hellotry:int(s1)except IndexError as e: # 未捕获到异常程序直接报错print e#2 多分支s1 hellotry:int(s1)except IndexError as e:print(e)except KeyError as e:print(e)except ValueError as e:print(e)#3 万能异常Exceptions1 hellotry:int(s1)except Exception as e:print(e)#4 多分支异常与万能异常#4.1 如果你想要的效果是无论出现什么异常我们统一丢弃或者使用同一段代码逻辑去处理他们那么骚年大胆的去做吧只有一个Exception就足够了。#4.2 如果你想要的效果是对于不同的异常我们需要定制不同的处理逻辑那就需要用到多分支了。#5 也可以在多分支后来一个Exceptions1 hellotry:int(s1)except IndexError as e:print(e)except KeyError as e:print(e)except ValueError as e:print(e)except Exception as e:print(e)#6 异常的其他机构s1 hellotry:int(s1)except IndexError as e:print(e)except KeyError as e:print(e)except ValueError as e:print(e)#except Exception as e:# print(e)else:print(try内代码块没有异常则执行我)finally:print(无论异常与否,都会执行该模块,通常是进行清理工作)#7 主动触发异常try:raise TypeError(类型错误)except Exception as e:print(e)#8 自定义异常class EgonException(BaseException):def __init__(self,msg):self.msgmsgdef __str__(self):return self.msgtry:raise EgonException(类型错误)except EgonException as e:print(e)#9 断言:assert 条件assert 1 1 assert 1 2#10 总结try..except1把错误处理和真正的工作分开来2代码更易组织更清晰复杂的工作任务更容易实现3毫无疑问更安全了不至于由于一些小的疏忽而使程序意外崩溃了 异常分类使用 1.3.3 如何处理异常实例 #3、如何处理异常# print(start)## try:# l[]# print(l[1111])# print(1)# print(2)# print(3)# except IndexError:# pass## print(end)# print(start)# try:# l[]# print(l[1111])# print(1)# print(2)# print(3)# except IndexError as e:# print(,e)## print(end)# print(start)# try:# l[]# # print(l[1111])# print(1)# d{}# d[k]# print(2)# print(3)# except IndexError as e:# print(,e)# except KeyError as e:# print(----,e)## print(end)# print(start)# try:# l[]# # print(l[1111])# print(1)# d{}# d[k]# print(2)# print(3)# except IndexError:# pass# except KeyError:# pass# except Exception as e:# print(万能异常---,e)## print(end)# print(start)# try:# l[]# print(l[1111])# # print(1)# d{}# # d[k]# # print(2)# # print(3)# except IndexError:# pass# except KeyError:# pass# except Exception as e:# print(万能异常---,e)# else:# print(没有异常发生的时候触发)# finally:# print(有没有异常都触发)### print(end)try:connconnect(1.1.1.1,3306)conn.execute(select * from db1.t1)finally:conn.close()# stus[egon,alex,wxxx]ip_list[# 1.1.1.1:8080,# 1.1.1.2:8081,# 1.1.1.3:8082,]# if len(ip_list) 0:# raise TypeError# assert len(ip_list) 0# print(从ip_list取出ip地址验证可用性)# class MyException(BaseException):# def __init__(self,msg):# super(MyException,self).__init__()# self.msgmsg## def __str__(self):# return %s %self.msg## raise MyException(类型错误) #异常的值print(obj)
ageinput(: )if age.isdigit():ageint(age)if age 50:print(too big) 如何处理异常实例 1.4 什么时候用异常处理 有的同学会这么想学完了异常处理后好强大我要为我的每一段程序都加上try...except干毛线去思考它会不会有逻辑错误啊这样就很好啊多省脑细胞》2B青年欢乐多 首先try...except是你附加给你的程序的一种异常处理的逻辑与你的主要的工作是没有关系的这种东西加的多了会导致你的代码可读性变差 然后异常处理本就不是你2b逻辑的擦屁股纸只有在错误发生的条件无法预知的情况下才应该加上try...except其他的逻辑错误应该尽量修正。 第2章 网络编程 2.1 楔子 你现在已经学会了写python代码假如你写了两个python文件a.py和b.py分别去运行你就会发现这两个python的文件分别运行的很好。但是如果这两个程序之间想要传递一个数据你要怎么做呢 这个问题以你现在的知识就可以解决了我们可以创建一个文件把a.py想要传递的内容写到文件中然后b.py从这个文件中读取内容就可以了。 但是当你的a.py和b.py分别在不同电脑上的时候你要怎么办呢 类似的机制有计算机网盘qq等等。我们可以在我们的电脑上和别人聊天可以在自己的电脑上向网盘中上传、下载内容。这些都是两个程序在通信。 2.2 软件开发的架构 我们了解的涉及到两个程序之间通讯的应用大致可以分为两种 第一种是应用类qq、微信、网盘、优酷这一类是属于需要安装的桌面应用 第二种是web类比如百度、知乎、博客园等使用浏览器访问就可以直接使用的应用 这些应用的本质其实都是两个程序之间的通讯。而这两个分类又对应了两个软件开发的架构 2.2.1 C/S架构 C/S即Client与Server 中文意思客户端与服务器端架构这种架构也是从用户层面也可以是物理层面来划分的。 这里的客户端一般泛指客户端应用程序EXE程序需要先安装后才能运行在用户的电脑上对用户的电脑操作系统环境依赖较大。 2.2.2 B/S架构 B/S即Browser与Server,中文意思浏览器端与服务器端架构这种架构是从用户层面来划分的。 Browser浏览器其实也是一种Client客户端只是这个客户端不需要大家去安装什么应用程序只需在浏览器上通过HTTP请求服务器端相关的资源网页资源客户端Browser浏览器就能进行增删改查。 2.3 网络基础 2.3.1 详细请见外链地址 http://www.cnblogs.com/Eva-J/articles/8066842.html 或者 http://www.cnblogs.com/linhaifeng/articles/5937962.html 2.3.2 一个程序如何在网络上找到另一个程序 首先程序必须要启动其次必须有这台机器的地址我们都知道我们人的地址大概就是国家\省\市\区\街道\楼\门牌号这样字。那么每一台联网的机器在网络上也有自己的地址它的地址是怎么表示的呢 就是使用一串数字来表示的例如100.4.5.6 #########################什么是ip地址############################IP地址是指互联网协议地址英语Internet Protocol Address又译为网际协议地址是IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式它为互联网上的每一个网络和每一台主机分配一个逻辑地址以此来屏蔽物理地址的差异。
IP地址是一个32位的二进制数通常被分割为4个“8位二进制数”也就是4个字节。IP地址通常用“点分十进制”表示成a.b.c.d的形式其中a,b,c,d都是0~255之间的十进制整数。例点分十进IP地址100.4.5.6实际上是32位二进制数01100100.00000100.00000101.00000110。 #####################什么是端口#########################端口是英文port的意译可以认为是设备与外界通讯交流的出口。因此ip地址精确到具体的一台电脑而端口精确到具体的程序。 2.4 osi七层模型 2.4.1 引子 须知一个完整的计算机系统是由硬件、操作系统、应用软件三者组成,具备了这三个条件一台计算机系统就可以自己跟自己玩了打个单机游戏玩个扫雷啥的 如果你要跟别人一起玩那你就需要上网了什么是互联网 互联网的核心就是由一堆协议组成协议就是标准比如全世界人通信的标准是英语如果把计算机比作人互联网协议就是计算机界的英语。所有的计算机都学会了互联网协议那所有的计算机都就可以按照统一的标准去收发信息从而完成通信了。 2.4.2 osi七层模型 人们按照分工不同把互联网协议从逻辑上划分了层级 2.4.3 为何学习socket一定要先学习互联网协议 为何学习socket一定要先学习互联网协议 1.首先本节课程的目标就是教会你如何基于socket编程来开发一款自己的C/S架构软件 2.其次C/S架构的软件软件属于应用层是基于网络进行通信的 3.然后网络的核心即一堆协议协议即标准你想开发一款基于网络通信的软件就必须遵循这些标准。 4.最后就让我们从这些标准开始研究开启我们的socket编程之旅 2.5 socket概念 2.5.1 socket层 2.5.2 理解socket Socket是应用层与TCP/IP协议族通信的中间软件抽象层它是一组接口。在设计模式中Socket其实就是一个门面模式它把复杂的TCP/IP协议族隐藏在Socket接口后面对用户来说一组简单的接口就是全部让Socket去组织数据以符合指定的协议。 ###################站在你的角度上看socket########################其实站在你的角度上看socket就是一个模块。我们通过调用模块中已经实现的方法建立两个进程之间的连接和通信。也有人将socket说成ipport因为ip是用来标识互联网中的一台主机的位置而port是用来标识这台机器上的一个应用程序。所以我们只要确立了ip和port就能找到一个应用程序并且使用socket模块来与之通信。 2.6 套接字socket的发展史 套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种或者称为有两个种族,分别是基于文件型的和基于网络型的。 2.6.1 基于文件类型的套接字家族 套接字家族的名字AF_UNIX unix一切皆文件基于文件的套接字调用的就是底层的文件系统来取数据两个套接字进程运行在同一机器可以通过访问同一个文件系统间接完成通信 2.6.2 基于网络类型的套接字家族 套接字家族的名字AF_INET (还有AF_INET6被用于ipv6还有一些其他的地址家族不过他们要么是只用于某个平台要么就是已经被废弃或者是很少被使用或者是根本没有实现所有地址家族中AF_INET是使用最广泛的一个python支持很多种地址家族但是由于我们只关心网络编程所以大部分时候我么只使用AF_INET) 2.7 套接字工作流程 一个生活中的场景。你要打电话给一个朋友先拨号朋友听到电话铃声后提起电话这时你和你的朋友就建立起了连接就可以讲话了。等交流结束挂断电话结束此次交谈。 生活中的场景就解释了这工作原理。 先从服务器端说起。服务器端先初始化Socket然后与端口绑定(bind)对端口进行监听(listen)调用accept阻塞等待客户端连接。在这时如果有个客户端初始化一个Socket然后连接服务器(connect)如果连接成功这时客户端与服务器端的连接就建立了。客户端发送数据请求服务器端接收请求并处理请求然后把回应数据发送给客户端客户端读取数据最后关闭连接一次交互结束 2.7.1 socket()模块函数用法 import socketsocket.socket(socket_family,socket_type,protocal0)socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。获取tcp/ip套接字tcpSock socket.socket(socket.AF_INET, socket.SOCK_STREAM)获取udp/ip套接字udpSock socket.socket(socket.AF_INET, socket.SOCK_DGRAM)由于 socket 模块中有太多的属性。我们在这里破例使用了from module import *语句。使用 from socket import *,我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。例如tcpSock socket(AF_INET, SOCK_STREAM) socket()模块函数用法 2.7.2 服务端套接字函数 s.bind() 绑定(主机,端口号)到套接字 s.listen() 开始TCP监听 s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来 2.7.3 客户端套接字函数 s.connect() 主动初始化TCP服务器连接 s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 2.7.4 公共用途的套接字函数 s.recv() 接收TCP数据 s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完) s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完) s.recvfrom() 接收UDP数据 s.sendto() 发送UDP数据 s.getpeername() 连接到当前套接字的远端的地址 s.getsockname() 当前套接字的地址 s.getsockopt() 返回指定套接字的参数 s.setsockopt() 设置指定套接字的参数 s.close() 关闭套接字 2.7.5 面向锁的套接字方法 s.setblocking() 设置套接字的阻塞与非阻塞模式 s.settimeout() 设置阻塞套接字操作的超时时间 s.gettimeout() 得到阻塞套接字操作的超时时间 2.7.6 面向文件的套接字的函数 s.fileno() 套接字的文件描述符 s.makefile() 创建一个与该套接字相关的文件 2.7.7 socket实验推演流程 1用打电话的流程快速描述socket通信2服务端和客户端加上基于一次链接的循环通信3客户端发送空卡主证明是从哪个位置卡的服务端from socket import *phonesocket(AF_INET,SOCK_STREAM)phone.bind((127.0.0.1,8081))phone.listen(5)conn,addrphone.accept()while True:dataconn.recv(1024)print(server)print(data)conn.send(data.upper())conn.close()phone.close()客户端from socket import *phonesocket(AF_INET,SOCK_STREAM)phone.connect((127.0.0.1,8081))while True:msginput(: ).strip()phone.send(msg.encode(utf-8))print(client)dataphone.recv(1024)print(data)说明卡的原因缓冲区为空recv就卡住引出原理图4.演示客户端断开链接服务端的情况提供解决方法5.演示服务端不能重复接受链接而服务器都是正常运行不断来接受客户链接的6:简单演示udp服务端from socket import *phonesocket(AF_INET,SOCK_DGRAM)phone.bind((127.0.0.1,8082))while True:msg,addrphone.recvfrom(1024)phone.sendto(msg.upper(),addr)客户端from socket import *phonesocket(AF_INET,SOCK_DGRAM)while True:msginput(: )phone.sendto(msg.encode(utf-8),(127.0.0.1,8082))msg,addrphone.recvfrom(1024)print(msg)udp客户端可以并发演示udp客户端可以输入为空演示说出recvfrom与recv的区别暂且不提tcp流和udp报的概念留到粘包去说 socket实验推演流程 2.8 基于TCP的套接字 tcp是基于链接的必须先启动服务端然后再启动客户端去链接服务端 2.8.1 实例一server端与client端 #################server端#################import socketsk socket.socket()sk.bind((127.0.0.1,8898)) #把地址绑定到套接字sk.listen() #监听链接conn,addr sk.accept() #接受客户端链接ret conn.recv(1024) #接收客户端信息print(ret) #打印客户端信息conn.send(bhi) #向客户端发送信息conn.close() #关闭客户端套接字sk.close() #关闭服务器套接字(可选) server端 #####################client端############################import socketsk socket.socket() # 创建客户套接字sk.connect((127.0.0.1,8898)) # 尝试连接服务器sk.send(bhello!)ret sk.recv(1024) # 对话(发送/接收)print(ret)sk.close() # 关闭客户套接字 client端 2.8.2 问题有的同学在重启服务端时可能会遇到 ##################解决方法####################加入一条socket配置重用ip和端口import socketfrom socket import SOL_SOCKET,SO_REUSEADDRsk socket.socket()sk.setsockopt(SOL_SOCKET,SO_REUSEADDR,1) #就是它在bind前加sk.bind((127.0.0.1,8898)) #把地址绑定到套接字sk.listen() #监听链接conn,addr sk.accept() #接受客户端链接ret conn.recv(1024) #接收客户端信息print(ret) #打印客户端信息conn.send(bhi) #向客户端发送信息conn.close() #关闭客户端套接字sk.close() #关闭服务器套接字(可选) 解决方法 2.8.3 实例二server端与client端 ##################server端######################import socket#1、买手机phonesocket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议#2、绑定手机# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)phone.bind((127.0.0.1,8081)) #0-65535#3、开机phone.listen(5)#4、等待电话连接print(starting...)conn,client_addrphone.accept() #(conn,client_addr)print(conn,client_addr)#5、收\发消息dataconn.recv(1024) #1024bytes?
conn.send(data.upper())#6、挂电话连接conn.close()#7、关机phone.close() server端 ################client端####################import socket#1、买手机phonesocket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议#2、拨电话phone.connect((127.0.0.1,8081)) #0-65535#3、发收消息phone.send(hello.encode(utf-8))dataphone.recv(1024)print(data)#4、挂电话phone.close() client端 2.8.4 实例二加上链接循环与通信循环进阶版 模拟一个服务端三个客户端连接通信 #######################服务端进阶版###########################import socketphonesocket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议# print(phone)# phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)phone.bind((127.0.0.1,8083)) #0-65535phone.listen(5)print(starting...)while True: #链接循环
conn,client_addrphone.accept() #(conn,client_addr)# print(conn,client_addr)print(client_addr)while True: #通信循环try:dataconn.recv(1024) #1024bytes?if not data:break #针对的是linux系统print(客户端消息,data)conn.send(data.upper())# print(has send)except ConnectionResetError:breakconn.close()phone.close() 服务端进阶版 #############client端一进阶版#####################import socketphonesocket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议phone.connect((127.0.0.1,8083)) #0-65535while True:msginput(: ) #msg if not msg:continuephone.send(msg.encode(utf-8))# print(has send)
dataphone.recv(1024)# print(has recv)print(data)phone.close() client端一进阶版 #############client端二进阶版#####################import socketphonesocket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议phone.connect((127.0.0.1,8083)) #0-65535while True:msginput(: ).strip()if not msg:continuephone.send(msg.encode(utf-8))# print(has send)
dataphone.recv(1024)# print(has recv)print(data)phone.close() client端二进阶版 #############client端三进阶版#####################import socketphonesocket.socket(socket.AF_INET,socket.SOCK_STREAM) #tcp协议phone.connect((127.0.0.1,8083)) #0-65535while True:msginput(: ).strip()if not msg:continuephone.send(msg.encode(utf-8))# print(has send)
dataphone.recv(1024)# print(has recv)print(data)phone.close() client端三进阶版 2.8.5 实现ssh远程执行命令 #################服务端##################from socket import *import subprocessserversocket(AF_INET,SOCK_STREAM)server.bind((127.0.0.1,8090))server.listen(5)while True:conn,client_addrserver.accept()print(client_addr)while True:try:cmdconn.recv(1024)if not cmd:break#ls -l;sadfasdf;pwd;echo 123
objsubprocess.Popen(cmd.decode(utf-8),shellTrue,stdoutsubprocess.PIPE,stderrsubprocess.PIPE)stdoutobj.stdout.read()stderrobj.stderr.read()cmd_resstdoutstderrprint(len(cmd_res))conn.send(cmd_res)except ConnectionResetError:breakconn.close()server.close() 服务端 #####################client端#################from socket import *clientsocket(AF_INET,SOCK_STREAM)client.connect((127.0.0.1,8090))while True:cmdinput(: ).strip()if not cmd:continueclient.send(cmd.encode(utf-8))dataclient.recv(1024)print(data.decode(gbk))client.close() client端 2.9 基于UDP协议的socket udp是无链接的先启动哪一端都不会报错 2.9.1 简单使用 ###################server端#####################import socketudp_sk socket.socket(typesocket.SOCK_DGRAM) #创建一个服务器的套接字udp_sk.bind((127.0.0.1,9000)) #绑定服务器套接字msg,addr udp_sk.recvfrom(1024)print(msg)udp_sk.sendto(bhi,addr) # 对话(接收与发送)udp_sk.close() # 关闭服务器套接字 server端 #######################client端#######################import socketip_port(127.0.0.1,9000)udp_sksocket.socket(typesocket.SOCK_DGRAM)udp_sk.sendto(bhello,ip_port)back_msg,addrudp_sk.recvfrom(1024)print(back_msg.decode(utf-8),addr) client端 2.9.2 qq聊天 #################server端##############################_*_coding:utf-8_*_import socketip_port(127.0.0.1,8081)udp_server_socksocket.socket(socket.AF_INET,socket.SOCK_DGRAM)udp_server_sock.bind(ip_port)while True:qq_msg,addrudp_server_sock.recvfrom(1024)print(来自[%s:%s]的一条消息:\033[1;44m%s\033[0m %(addr[0],addr[1],qq_msg.decode(utf-8)))back_msginput(回复消息: ).strip()udp_server_sock.sendto(back_msg.encode(utf-8),addr) server端 ##################################client端######################_*_coding:utf-8_*_import socketBUFSIZE1024udp_client_socketsocket.socket(socket.AF_INET,socket.SOCK_DGRAM)qq_name_dic{金老板:(127.0.0.1,8081),哪吒:(127.0.0.1,8081),egg:(127.0.0.1,8081),yuan:(127.0.0.1,8081),}while True:qq_nameinput(请选择聊天对象: ).strip()while True:msginput(请输入消息,回车发送,输入q结束和他的聊天: ).strip()if msg q:breakif not msg or not qq_name or qq_name not in qq_name_dic:continueudp_client_socket.sendto(msg.encode(utf-8),qq_name_dic[qq_name])back_msg,addrudp_client_socket.recvfrom(BUFSIZE)print(来自[%s:%s]的一条消息:\033[1;44m%s\033[0m %(addr[0],addr[1],back_msg.decode(utf-8)))udp_client_socket.close() client端 2.9.3 时间服务器 #################server端############################## _*_coding:utf-8_*_from socket import *from time import strftimeip_port (127.0.0.1, 9000)bufsize 1024tcp_server socket(AF_INET, SOCK_DGRAM)tcp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)tcp_server.bind(ip_port)while True:msg, addr tcp_server.recvfrom(bufsize)print(, msg)if not msg:time_fmt %Y-%m-%d %Xelse:time_fmt msg.decode(utf-8)back_msg strftime(time_fmt)tcp_server.sendto(back_msg.encode(utf-8), addr)tcp_server.close() server端 #################client端##############################_*_coding:utf-8_*_from socket import *ip_port(127.0.0.1,9000)bufsize1024tcp_clientsocket(AF_INET,SOCK_DGRAM)while True:msginput(请输入时间格式(例%Y %m %d): ).strip()tcp_client.sendto(msg.encode(utf-8),ip_port)datatcp_client.recv(bufsize) client端 2.10 socket参数的详解 socket.socket(familyAF_INET,typeSOCK_STREAM,proto0,filenoNone) 创建socket对象的参数说明 family 地址系列应为AF_INET(默认值),AF_INET6,AF_UNIX,AF_CAN或AF_RDS。 AF_UNIX 域实际上是使用本地 socket 文件来通信 type 套接字类型应为SOCK_STREAM(默认值),SOCK_DGRAM,SOCK_RAW或其他SOCK_常量之一。SOCK_STREAM 是基于TCP的有保障的即能保证数据正确传送到对方面向连接的SOCKET多用于资料传送。 SOCK_DGRAM 是基于UDP的无保障的面向消息的socket多用于在网络上发广播信息。 proto 协议号通常为零,可以省略,或者在地址族为AF_CAN的情况下,协议应为CAN_RAW或CAN_BCM之一。 fileno 如果指定了fileno,则其他参数将被忽略,导致带有指定文件描述符的套接字返回。 与socket.fromfd()不同,fileno将返回相同的套接字,而不是重复的。 这可能有助于使用socket.close()关闭一个独立的插座。 2.11 粘包 2.11.1 黏包现象 让我们基于tcp先制作一个远程执行命令的程序命令ls -l ; lllllll ; pwd ###########################注意#########################ressubprocess.Popen(cmd.decode(utf-8),shellTrue,stderrsubprocess.PIPE,stdoutsubprocess.PIPE)的结果的编码是以当前所在的系统为准的如果是windows那么res.stdout.read()读出的就是GBK编码的在接收端需要用GBK解码
且只能从管道里读一次结果 同时执行多条命令之后得到的结果很可能只有一部分在执行其他命令的时候又接收到之前执行的另外一部分结果这种显现就是黏包。 2.11.2 基于tcp协议实现的黏包 ########################tcp - server####################_*_coding:utf-8_*_from socket import *import subprocessip_port(127.0.0.1,8888)BUFSIZE1024tcp_socket_serversocket(AF_INET,SOCK_STREAM)tcp_socket_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)tcp_socket_server.bind(ip_port)tcp_socket_server.listen(5)while True:conn,addrtcp_socket_server.accept()print(客户端,addr)while True:cmdconn.recv(BUFSIZE)if len(cmd) 0:breakressubprocess.Popen(cmd.decode(utf-8),shellTrue,stdoutsubprocess.PIPE,stdinsubprocess.PIPE,stderrsubprocess.PIPE)stderrres.stderr.read()stdoutres.stdout.read()conn.send(stderr)conn.send(stdout) tcp - server ######################tcp - client########################_*_coding:utf-8_*_import socketBUFSIZE1024ip_port(127.0.0.1,8888)ssocket.socket(socket.AF_INET,socket.SOCK_STREAM)ress.connect_ex(ip_port)while True:msginput(: ).strip()if len(msg) 0:continueif msg quit:breaks.send(msg.encode(utf-8))act_ress.recv(BUFSIZE)print(act_res.decode(utf-8),end) tcp - client 2.11.3 基于tcp协议黏包现象实例二 #################server端###################from socket import *import timeserversocket(AF_INET,SOCK_STREAM)server.bind((127.0.0.1,8091))server.listen(5)conn,addrserver.accept()#bhellores1conn.recv(5) #bhprint(res1: ,res1)# belloworldtime.sleep(6)res2conn.recv(5)print(res2: ,res2)conn.close()server.close() server端 ######################client端##############################from socket import *import timeclientsocket(AF_INET,SOCK_STREAM)client.connect((127.0.0.1,8091))client.send(hello.encode(utf-8)) #bhellotime.sleep(5)client.send(world.encode(utf-8)) #bworld
client.close() client端 2.11.4 基于udp协议实现的黏包 #################udp - server#######################_*_coding:utf-8_*_from socket import *import subprocessip_port(127.0.0.1,9000)bufsize1024udp_serversocket(AF_INET,SOCK_DGRAM)udp_server.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)udp_server.bind(ip_port)while True:#收消息
cmd,addrudp_server.recvfrom(bufsize)print(用户命令-----,cmd)#逻辑处理
ressubprocess.Popen(cmd.decode(utf-8),shellTrue,stderrsubprocess.PIPE,stdinsubprocess.PIPE,stdoutsubprocess.PIPE)stderrres.stderr.read()stdoutres.stdout.read()#发消息
udp_server.sendto(stderr,addr)udp_server.sendto(stdout,addr)udp_server.close() udp - server ######################udp - client#############################from socket import *ip_port(127.0.0.1,9000)bufsize1024udp_clientsocket(AF_INET,SOCK_DGRAM)while True:msginput(: ).strip()udp_client.sendto(msg.encode(utf-8),ip_port)err,addrudp_client.recvfrom(bufsize)out,addrudp_client.recvfrom(bufsize)if err:print(error : %s%err.decode(utf-8),end)if out:print(out.decode(utf-8), end) udp - client 注意只有TCP有粘包现象UDP永远不会粘包 2.12 黏包成因 2.12.1 TCP协议中的数据传递 ##################tcp协议的拆包机制###################当发送端缓冲区的长度大于网卡的MTU时tcp会将这次发送的数据拆成几个数据包发送出去。MTU是Maximum Transmission Unit的缩写。意思是网络上传送的最大数据包。MTU的单位是字节。 大部分网络设备的MTU都是1500。如果本机的MTU比网关的MTU大大的数据包就会被拆开来传送这样会产生很多数据包碎片增加丢包率降低网络速度。 #########################面向流的通信特点和Nagle算法##############################TCPtransport control protocol传输控制协议是面向连接的面向流的提供高可靠性服务。收发两端客户端和服务器端都要有一一成对的socket因此发送端为了将多个发往接收端的包更有效的发到对方使用了优化方法Nagle算法将多次间隔较小且数据量小的数据合并成一个大的数据块然后进行封包。这样接收端就难于分辨出来了必须提供科学的拆包机制。 即面向流的通信是无消息保护边界的。对于空消息tcp是基于数据流的于是收发的消息不能为空这就需要在客户端和服务端都添加空消息的处理机制防止程序卡住而udp是基于数据报的即便是你输入的是空内容直接回车也可以被发送udp协议会帮你封装上消息头发送过去。可靠黏包的tcp协议tcp的协议数据不会丢没有收完包下次接收会继续上次继续接收己端总是在收到ack时才会清除缓冲区内容。数据是可靠的但是会粘包。 ##################基于tcp协议特点的黏包现象成因############# ##############socket数据传输过程中的用户态与内核态说明################例如基于tcp的套接字客户端往服务端上传文件发送时文件内容是按照一段一段的字节流发送的在接收方看了根本不知道该文件的字节流从何处开始在何处结束此外发送方引起的粘包是由TCP协议本身造成的TCP为提高传输效率发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去这样接收方就收到了粘包数据。 2.12.2 UDP不会发生黏包 UDPuser datagram protocol用户数据报协议是无连接的面向消息的提供高效率服务。不会使用块的合并优化算法, 由于UDP支持的是一对多的模式所以接收端的skbuff(套接字缓冲区采用了链式结构来记录每一个到达的UDP包在每个UDP包中就有了消息头消息来源地址端口等信息这样对于接收端来说就容易进行区分处理了。 即面向消息的通信是有消息保护边界的。对于空消息tcp是基于数据流的于是收发的消息不能为空这就需要在客户端和服务端都添加空消息的处理机制防止程序卡住而udp是基于数据报的即便是你输入的是空内容直接回车也可以被发送udp协议会帮你封装上消息头发送过去。不可靠不黏包的udp协议udp的recvfrom是阻塞的一个recvfrom(x)必须对唯一一个sendinto(y),收完了x个字节的数据就算完成,若是y;x数据就丢失这意味着udp根本不会粘包但是会丢数据不可靠。 补充说明: #####################udp和tcp一次发送数据长度的限制#####################用UDP协议发送时用sendto函数最大能发送数据的长度为65535- IP头(20) – UDP头(8)65507字节。用sendto函数发送数据时如果发送数据长度大于该值则函数会返回错误。丢弃这个包不进行发送用TCP协议发送时由于TCP是数据流协议因此不存在包大小的限制暂不考虑缓冲区的大小这是指在用send函数时数据长度参数不受限制。而实际上所指定的这段数据并不一定会一次性发送出去如果这段数据比较长会被分段发送如果比较短可能会等待和下一次数据一起发送。 2.12.3 会发生黏包的两种情况 情况一 发送方的缓存机制 发送端需要等缓冲区满才发送出去造成粘包发送数据时间间隔很短数据了很小会合到一起产生粘包 #############################服务端######################_*_coding:utf-8_*_from socket import *ip_port(127.0.0.1,8080)tcp_socket_serversocket(AF_INET,SOCK_STREAM)tcp_socket_server.bind(ip_port)tcp_socket_server.listen(5)conn,addrtcp_socket_server.accept()data1conn.recv(10)data2conn.recv(10)print(-----,data1.decode(utf-8))print(-----,data2.decode(utf-8))conn.close() 服务端 ####################客户端#####################_*_coding:utf-8_*_import socketBUFSIZE1024ip_port(127.0.0.1,8080)ssocket.socket(socket.AF_INET,socket.SOCK_STREAM)ress.connect_ex(ip_port)s.send(hello.encode(utf-8))s.send(feng.encode(utf-8)) 客户端 情况二 接收方的缓存机制 接收方不及时接收缓冲区的包造成多个包接收客户端发送了一段数据服务端只收了一小部分服务端下次再收的时候还是从缓冲区拿上次遗留的数据产生粘包 #######################服务端##########################_*_coding:utf-8_*_from socket import *ip_port(127.0.0.1,8080)tcp_socket_serversocket(AF_INET,SOCK_STREAM)tcp_socket_server.bind(ip_port)tcp_socket_server.listen(5)conn,addrtcp_socket_server.accept()data1conn.recv(2) #一次没有收完整data2conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的print(-----,data1.decode(utf-8))print(-----,data2.decode(utf-8))conn.close() 服务端 ############################客户端##########################_*_coding:utf-8_*_import socketBUFSIZE1024ip_port(127.0.0.1,8080)ssocket.socket(socket.AF_INET,socket.SOCK_STREAM)ress.connect_ex(ip_port)s.send(hello feng.encode(utf-8)) 客户端 2.12.4 总结 黏包现象只发生在tcp协议中 1.从表面上看黏包问题主要是因为发送方和接收方的缓存机制、tcp协议面向流通信的特点。 2.实际上主要还是因为接收方不知道消息之间的界限不知道一次性提取多少字节的数据所造成的 2.13 黏包的解决方案一 问题的根源在于接收端不知道发送端将要传送的字节流的长度所以解决粘包的方法就是围绕如何让发送端在发送数据前把自己将要发送的字节流总大小让接收端知晓然后接收端来一个死循环接收完所有数据。 ###################服务端####################
#_*_coding:utf-8_*_import socket,subprocessip_port(127.0.0.1,8080)ssocket.socket(socket.AF_INET,socket.SOCK_STREAM)s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)s.bind(ip_port)s.listen(5)while True:conn,addrs.accept()print(客户端,addr)while True:msgconn.recv(1024)if not msg:breakressubprocess.Popen(msg.decode(utf-8),shellTrue,\stdinsubprocess.PIPE,\stderrsubprocess.PIPE,\stdoutsubprocess.PIPE)errres.stderr.read()if err:reterrelse:retres.stdout.read()data_lengthlen(ret)conn.send(str(data_length).encode(utf-8))dataconn.recv(1024).decode(utf-8)if data recv_ready:conn.sendall(ret)conn.close() 服务端 ##################客户端###################_*_coding:utf-8_*_import socket,timessocket.socket(socket.AF_INET,socket.SOCK_STREAM)ress.connect_ex((127.0.0.1,8080))while True:msginput(: ).strip()if len(msg) 0:continueif msg quit:breaks.send(msg.encode(utf-8))lengthint(s.recv(1024).decode(utf-8))s.send(recv_ready.encode(utf-8))send_size0recv_size0databwhile recv_size length:datas.recv(1024)recv_sizelen(data)print(data.decode(utf-8)) 客户端 存在的问题 程序的运行速度远快于网络传输速度所以在发送一段字节前先用send去发送该字节流长度这种方式会放大网络延迟带来的性能损耗。 2.14 解决方案进阶 刚刚的方法问题在于我们我们在发送 我们可以借助一个模块这个模块可以把要发送的数据长度转换成固定长度的字节。这样客户端每次接收消息之前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小那么最终接受的数据只要达到这个值就停止就能刚好不多不少的接收完整的数据了。 2.14.1 struct模块 该模块可以把一个类型如数字转成固定长度的bytes struct.pack(i,1111111111111)struct.error: i format requires -2147483648 number 2147483647 #这个是范围 import json,struct#假设通过客户端上传1T:1073741824000的文件a.txt#为避免粘包,必须自定制报头header{file_size:1073741824000,file_name:/a/b/c/d/e/a.txt,md5:8f6fbf8347faa4924a76856701edb0f3} #1T数据,文件路径和md5值#为了该报头能传送,需要序列化并且转为byteshead_bytesbytes(json.dumps(header),encodingutf-8) #序列化并转成bytes,用于传输#为了让客户端知道报头的长度,用struck将报头长度这个数字转成固定长度:4个字节head_len_bytesstruct.pack(i,len(head_bytes)) #这4个字节里只包含了一个数字,该数字是报头的长度#客户端开始发送conn.send(head_len_bytes) #先发报头的长度,4个bytesconn.send(head_bytes) #再发报头的字节格式conn.sendall(文件内容) #然后发真实内容的字节格式#服务端开始接收head_len_bytess.recv(4) #先收报头4个bytes,得到报头长度的字节格式xstruct.unpack(i,head_len_bytes)[0] #提取报头的长度
head_bytess.recv(x) #按照报头长度x,收取报头的bytes格式headerjson.loads(json.dumps(header)) #提取报头#最后根据报头的内容提取真实的数据,比如real_data_lens.recv(header[file_size])s.recv(real_data_len) ####################关于struct的详细用法######################_*_coding:utf-8_*_#http://www.cnblogs.com/coser/archive/2011/12/17/2291160.html__author__ Linhaifengimport structimport binasciiimport ctypesvalues1 (1, abc.encode(utf-8), 2.7)values2 (defg.encode(utf-8),101)s1 struct.Struct(I3sf)s2 struct.Struct(4sI)print(s1.size,s2.size)prebufferctypes.create_string_buffer(s1.sizes2.size)print(Before : ,binascii.hexlify(prebuffer))# tbinascii.hexlify(asdfaf.encode(utf-8))# print(t)
s1.pack_into(prebuffer,0,*values1)s2.pack_into(prebuffer,s1.size,*values2)print(After pack,binascii.hexlify(prebuffer))print(s1.unpack_from(prebuffer,0))print(s2.unpack_from(prebuffer,s1.size))s3struct.Struct(ii)s3.pack_into(prebuffer,0,123,123)print(After pack,binascii.hexlify(prebuffer))print(s3.unpack_from(prebuffer,0)) 关于struct的详细用法 2.14.2 使用struct解决黏包 借助struct模块我们知道长度数字可以被转换成一个标准大小的4字节数字。因此可以利用这个特点来预先发送数据长度。 发送时 接收时 先发送struct转换好的数据长度4字节 先接受4个字节使用struct转换成数字来获取要接收的数据长度 再发送数据 再按照长度接收数据 #################服务端自定制报头##################import socket,struct,jsonimport subprocessphonesocket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它在bind前加
phone.bind((127.0.0.1,8080))phone.listen(5)while True:conn,addrphone.accept()while True:cmdconn.recv(1024)if not cmd:breakprint(cmd: %s %cmd)ressubprocess.Popen(cmd.decode(utf-8),shellTrue,stdoutsubprocess.PIPE,stderrsubprocess.PIPE)errres.stderr.read()print(err)if err:back_msgerrelse:back_msgres.stdout.read()conn.send(struct.pack(i,len(back_msg))) #先发back_msg的长度
conn.sendall(back_msg) #在发真实的内容
conn.close() 服务端自定制报头 #####################客户端自定制报头#######################_*_coding:utf-8_*_import socket,time,structssocket.socket(socket.AF_INET,socket.SOCK_STREAM)ress.connect_ex((127.0.0.1,8080))while True:msginput(: ).strip()if len(msg) 0:continueif msg quit:breaks.send(msg.encode(utf-8))ls.recv(4)xstruct.unpack(i,l)[0]print(type(x),x)# print(struct.unpack(I,l))
r_s0databwhile r_s x:r_ds.recv(1024)datar_dr_slen(r_d)# print(data.decode(utf-8))print(data.decode(gbk)) #windows默认gbk编码 客户端自定制报头 2.14.3 使用struct与json序列化解决黏包 我们还可以把报头做成字典字典里包含将要发送的真实数据的详细信息然后json序列化然后用struck将序列化后的数据长度打包成4个字节4个自己足够用了 发送时 接收时 先发报头长度 先收报头长度用struct取出来 再编码报头内容然后发送 根据取出的长度收取报头内容然后解码反序列化 最后发真实内容 从反序列化的结果中取出待取数据的详细信息然后去取真实的数据内容 #############服务端定制稍微复杂一点的报头#################import socket,struct,jsonimport subprocessphonesocket.socket(socket.AF_INET,socket.SOCK_STREAM)phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) #就是它在bind前加
phone.bind((127.0.0.1,8080))phone.listen(5)while True:conn,addrphone.accept()while True:cmdconn.recv(1024)if not cmd:breakprint(cmd: %s %cmd)ressubprocess.Popen(cmd.decode(utf-8),shellTrue,stdoutsubprocess.PIPE,stderrsubprocess.PIPE)errres.stderr.read()print(err)if err:back_msgerrelse:back_msgres.stdout.read()headers{data_size:len(back_msg)}head_jsonjson.dumps(headers)head_json_bytesbytes(head_json,encodingutf-8)conn.send(struct.pack(i,len(head_json_bytes))) #先发报头的长度
conn.send(head_json_bytes) #再发报头
conn.sendall(back_msg) #在发真实的内容
conn.close() 服务端定制稍微复杂一点的报头 #########################客户端#########################from socket import *import struct,jsonip_port(127.0.0.1,8080)clientsocket(AF_INET,SOCK_STREAM)client.connect(ip_port)while True:cmdinput(: )if not cmd:continueclient.send(bytes(cmd,encodingutf-8))headclient.recv(4)head_json_lenstruct.unpack(i,head)[0]head_jsonjson.loads(client.recv(head_json_len).decode(utf-8))data_lenhead_json[data_size]recv_size0recv_databwhile recv_size data_len:recv_dataclient.recv(1024)recv_sizelen(recv_data)print(recv_data.decode(utf-8))#print(recv_data.decode(gbk)) #windows默认gbk编码 客户端 2.15 课堂讲解实例解决粘包问题版本1 2.15.1 struct模块的使用 ####################struct模块的使用#################import structheadersstruct.pack(i,132333)# print(headers,len(headers))
resstruct.unpack(i,headers)print(res[0]) struct模块的使用 2.15.2 服务端 ###################服务端#############from socket import *import subprocessimport structserversocket(AF_INET,SOCK_STREAM)server.bind((127.0.0.1,8093))server.listen(5)while True:conn,client_addrserver.accept()print(client_addr)while True:try:cmdconn.recv(8096)if not cmd:break#ls -l;sadfasdf;pwd;echo 123
objsubprocess.Popen(cmd.decode(utf-8),shellTrue,stdoutsubprocess.PIPE,stderrsubprocess.PIPE)stdoutobj.stdout.read()stderrobj.stderr.read()#1、制作固定长度的报头
total_size len(stdout) len(stderr)headersstruct.pack(i,total_size)#2、先发送命令长度
conn.send(headers)#3、发送命令的执行结果
conn.send(stdout)conn.send(stderr)except ConnectionResetError:breakconn.close()server.close() 服务端 2.15.3 客户端 ##########################客户端######################from socket import *import structclientsocket(AF_INET,SOCK_STREAM)client.connect((127.0.0.1,8093))while True:cmdinput(: ).strip()if not cmd:continueclient.send(cmd.encode(utf-8))#1、先接收命令长度
headersclient.recv(4)total_size struct.unpack(i, headers)[0]#2、再收命令的结果
recv_size0databwhile recv_size total_size:recv_dataclient.recv(1024)datarecv_datarecv_sizelen(recv_data)print(data.decode(gbk))client.close() 客户端 2.16 课堂讲解实例解决粘包问题版本2 2.16.1 struct模块的使用 ##################### struct模块的使用###################import struct# headersstruct.pack(q,13233322222222222)# print(headers,len(headers))# resstruct.unpack(i,headers)# print(res[0])import jsonheaders{filepath : a.txt,md5 : 123sxd123x123,total_size : 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111213123123123123123123111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111}headers_jsonjson.dumps(headers)headers_bytesheaders_json.encode(utf-8)# print(len(headers_bytes))resstruct.pack(i,len(headers_bytes))print(res,len(res)) struct模块的使用 2.16.2 服务端 ##########################服务端######################from socket import *import subprocessimport structimport jsonserversocket(AF_INET,SOCK_STREAM)server.bind((127.0.0.1,8093))server.listen(5)while True:conn,client_addrserver.accept()print(client_addr)while True:try:cmdconn.recv(8096)if not cmd:break#ls -l;sadfasdf;pwd;echo 123
objsubprocess.Popen(cmd.decode(utf-8),shellTrue,stdoutsubprocess.PIPE,stderrsubprocess.PIPE)stdoutobj.stdout.read()stderrobj.stderr.read()#1、制作报头
headers {filepath: a.txt,md5: 123sxd123x123,total_size: len(stdout) len(stderr)}headers_json json.dumps(headers)headers_bytes headers_json.encode(utf-8)#2、先发报头的长度
conn.send(struct.pack(i,len(headers_bytes)))#3、发送报头
conn.send(headers_bytes)#4、发送命令的执行结果
conn.send(stdout)conn.send(stderr)except ConnectionResetError:breakconn.close()server.close() 服务端 2.16.3 客户端 ######################客户端############################from socket import *import structimport jsonclientsocket(AF_INET,SOCK_STREAM)client.connect((127.0.0.1,8093))while True:cmdinput(: ).strip()if not cmd:continueclient.send(cmd.encode(utf-8))#1、先接收报头的长度
headers_sizestruct.unpack(i,client.recv(4))[0]#2、再收报头
headers_bytesclient.recv(headers_size)headers_jsonheaders_bytes.decode(utf-8)headers_dicjson.loads(headers_json)print(,headers_dic)total_sizeheaders_dic[total_size]#3、再收命令的结果
recv_size0databwhile recv_size total_size:recv_dataclient.recv(1024)datarecv_datarecv_sizelen(recv_data)print(data.decode(gbk))client.close() 客户端 2.17 FTP作业上传下载文件 2.17.1 原博客实例 ####################服务端#################import socketimport structimport jsonimport subprocessimport osclass MYTCPServer:address_family socket.AF_INETsocket_type socket.SOCK_STREAMallow_reuse_address Falsemax_packet_size 8192codingutf-8request_queue_size 5server_dirfile_uploaddef __init__(self, server_address, bind_and_activateTrue):Constructor. May be extended, do not override.self.server_addressserver_addressself.socket socket.socket(self.address_family,self.socket_type)if bind_and_activate:try:self.server_bind()self.server_activate()except:self.server_close()raisedef server_bind(self):Called by constructor to bind the socket.if self.allow_reuse_address:self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)self.socket.bind(self.server_address)self.server_address self.socket.getsockname()def server_activate(self):Called by constructor to activate the server.self.socket.listen(self.request_queue_size)def server_close(self):Called to clean-up the server.self.socket.close()def get_request(self):Get the request and client address from the socket.return self.socket.accept()def close_request(self, request):Called to clean up an individual request.request.close()def run(self):while True:self.conn,self.client_addrself.get_request()print(from client ,self.client_addr)while True:try:head_struct self.conn.recv(4)if not head_struct:breakhead_len struct.unpack(i, head_struct)[0]head_json self.conn.recv(head_len).decode(self.coding)head_dic json.loads(head_json)print(head_dic)#head_dic{cmd:put,filename:a.txt,filesize:123123}
cmdhead_dic[cmd]if hasattr(self,cmd):funcgetattr(self,cmd)func(head_dic)except Exception:breakdef put(self,args):file_pathos.path.normpath(os.path.join(self.server_dir,args[filename]))filesizeargs[filesize]recv_size0print(-----,file_path)with open(file_path,wb) as f:while recv_size filesize:recv_dataself.conn.recv(self.max_packet_size)f.write(recv_data)recv_sizelen(recv_data)print(recvsize:%s filesize:%s %(recv_size,filesize))tcpserver1MYTCPServer((127.0.0.1,8080))tcpserver1.run()#下列代码与本题无关class MYUDPServer:UDP server class.address_family socket.AF_INETsocket_type socket.SOCK_DGRAMallow_reuse_address Falsemax_packet_size 8192codingutf-8def get_request(self):data, client_addr self.socket.recvfrom(self.max_packet_size)return (data, self.socket), client_addrdef server_activate(self):# No need to call listen() for UDP.passdef shutdown_request(self, request):# No need to shutdown anything.
self.close_request(request)def close_request(self, request):# No need to close anything.pass 服务端 #####################客户端##################import socketimport structimport jsonimport osclass MYTCPClient:address_family socket.AF_INETsocket_type socket.SOCK_STREAMallow_reuse_address Falsemax_packet_size 8192codingutf-8request_queue_size 5def __init__(self, server_address, connectTrue):self.server_addressserver_addressself.socket socket.socket(self.address_family,self.socket_type)if connect:try:self.client_connect()except:self.client_close()raisedef client_connect(self):self.socket.connect(self.server_address)def client_close(self):self.socket.close()def run(self):while True:inpinput(: ).strip()if not inp:continuelinp.split()cmdl[0]if hasattr(self,cmd):funcgetattr(self,cmd)func(l)def put(self,args):cmdargs[0]filenameargs[1]if not os.path.isfile(filename):print(file:%s is not exists %filename)returnelse:filesizeos.path.getsize(filename)head_dic{cmd:cmd,filename:os.path.basename(filename),filesize:filesize}print(head_dic)head_jsonjson.dumps(head_dic)head_json_bytesbytes(head_json,encodingself.coding)head_structstruct.pack(i,len(head_json_bytes))self.socket.send(head_struct)self.socket.send(head_json_bytes)send_size0with open(filename,rb) as f:for line in f:self.socket.send(line)send_sizelen(line)print(send_size)else:print(upload successful)clientMYTCPClient((127.0.0.1,8080))client.run() 客户端 2.17.2 课堂讲解实例 #######################服务端#######################import socketimport osimport jsonimport structSHARE_DIRrF:\Python周末20期\day8\08 上传下载文件\SHAREclass FtpServer:def __init__(self,host,port):self.hosthostself.portportself.serversocket.socket(socket.AF_INET,socket.SOCK_STREAM)self.server.bind((self.host,self.port))self.server.listen(5)def serve_forever(self):print(server starting...)while True:self.conn,self.client_addrself.server.accept()print(self.client_addr)while True:try:dataself.conn.recv(1024) #params_json.encode(utf-8)if not data:breakparamsjson.loads(data.decode(utf-8)) #params[get,a.txt]
cmdparams[0] #
if hasattr(self,cmd):funcgetattr(self,cmd)func(params)else:print(\033[45mcmd not exists\033[0m)except ConnectionResetError:breakself.conn.close()self.server.close()def get(self,params): #params[get,a.txt]
filenameparams[1] #filenamea.txt
filepathos.path.join(SHARE_DIR,filename) #
if os.path.exists(filepath):#1、制作报头
headers {filename: filename,md5: 123sxd123x123,filesize: os.path.getsize(filepath)}headers_json json.dumps(headers)headers_bytes headers_json.encode(utf-8)#2、先发报头的长度
self.conn.send(struct.pack(i,len(headers_bytes)))#3、发送报头
self.conn.send(headers_bytes)#4、发送真实的数据
with open(filepath,rb) as f:for line in f:self.conn.send(line)def put(self):passif __name__ __main__:serverFtpServer(127.0.0.1,8081)server.serve_forever() 服务端 #####################客户端#######################import socketimport structimport jsonimport osDOWNLOAD_DIRrF:\Python周末20期\day8\08 上传下载文件\DOWNLOADclass FtpClient:def __init__(self,host,port):self.hosthostself.portportself.clientsocket.socket(socket.AF_INET,socket.SOCK_STREAM)self.client.connect((self.host,self.port))def interactive(self):while True:datainput(: ).strip() #get a.txtif not data:continueparamsdata.split() #parmas[get,a.txt]
cmdparams[0] #cmdgetif hasattr(self,cmd):funcgetattr(self,cmd)func(params) #func([get,a.txt])def get(self,params):params_jsonjson.dumps(params)self.client.send(params_json.encode(utf-8))# 1、先接收报头的长度
headers_size struct.unpack(i, self.client.recv(4))[0]# 2、再收报头
headers_bytes self.client.recv(headers_size)headers_json headers_bytes.decode(utf-8)headers_dic json.loads(headers_json)print(, headers_dic)filename headers_dic[filename]filesize headers_dic[filesize]filepath os.path.join(DOWNLOAD_DIR, filename)# 3、再收真实的数据
with open(filepath, wb) as f:recv_size 0while recv_size filesize:line self.client.recv(1024)recv_size len(line)f.write(line)print(下载成功)if __name__ __main__:clientFtpClient(127.0.0.1,8081)client.interactive() 客户端 2.18 认证客户端的链接合法性 如果你想在分布式系统中实现一个简单的客户端链接认证功能又不像SSL那么复杂那么利用hmac加盐的方式来实现 2.18.1 服务端 #######################服务端######################_*_coding:utf-8_*___author__ Linhaifengfrom socket import *import hmac,ossecret_keyblinhaifeng bang bang bangdef conn_auth(conn):认证客户端链接:param conn::return:print(开始验证新链接的合法性)msgos.urandom(32)conn.sendall(msg)hhmac.new(secret_key,msg)digesth.digest()responeconn.recv(len(digest))return hmac.compare_digest(respone,digest)def data_handler(conn,bufsize1024):if not conn_auth(conn):print(该链接不合法,关闭)conn.close()returnprint(链接合法,开始通信)while True:dataconn.recv(bufsize)if not data:breakconn.sendall(data.upper())def server_handler(ip_port,bufsize,backlog5):只处理链接:param ip_port::return:tcp_socket_serversocket(AF_INET,SOCK_STREAM)tcp_socket_server.bind(ip_port)tcp_socket_server.listen(backlog)while True:conn,addrtcp_socket_server.accept()print(新连接[%s:%s] %(addr[0],addr[1]))data_handler(conn,bufsize)if __name__ __main__:ip_port(127.0.0.1,9999)bufsize1024server_handler(ip_port,bufsize) 服务端 2.18.2 客户端(合法) #########################客户端(合法)######################_*_coding:utf-8_*___author__ Linhaifengfrom socket import *import hmac,ossecret_keyblinhaifeng bang bang bangdef conn_auth(conn):验证客户端到服务器的链接:param conn::return:msgconn.recv(32)hhmac.new(secret_key,msg)digesth.digest()conn.sendall(digest)def client_handler(ip_port,bufsize1024):tcp_socket_clientsocket(AF_INET,SOCK_STREAM)tcp_socket_client.connect(ip_port)conn_auth(tcp_socket_client)while True:datainput(: ).strip()if not data:continueif data quit:breaktcp_socket_client.sendall(data.encode(utf-8))responetcp_socket_client.recv(bufsize)print(respone.decode(utf-8))tcp_socket_client.close()if __name__ __main__:ip_port(127.0.0.1,9999)bufsize1024client_handler(ip_port,bufsize) 客户端(合法) 2.18.3 客户端(非法:不知道加密方式) ##########################客户端(非法:不知道加密方式)###################_*_coding:utf-8_*___author__ Linhaifengfrom socket import *def client_handler(ip_port,bufsize1024):tcp_socket_clientsocket(AF_INET,SOCK_STREAM)tcp_socket_client.connect(ip_port)while True:datainput(: ).strip()if not data:continueif data quit:breaktcp_socket_client.sendall(data.encode(utf-8))responetcp_socket_client.recv(bufsize)print(respone.decode(utf-8))tcp_socket_client.close()if __name__ __main__:ip_port(127.0.0.1,9999)bufsize1024client_handler(ip_port,bufsize) 客户端(非法:不知道加密方式) 2.18.4 客户端(非法:不知道secret_key) #########################客户端(非法:不知道secret_key)####################_*_coding:utf-8_*___author__ Linhaifengfrom socket import *import hmac,ossecret_keyblinhaifeng bang bang bang1111def conn_auth(conn):验证客户端到服务器的链接:param conn::return:msgconn.recv(32)hhmac.new(secret_key,msg)digesth.digest()conn.sendall(digest)def client_handler(ip_port,bufsize1024):tcp_socket_clientsocket(AF_INET,SOCK_STREAM)tcp_socket_client.connect(ip_port)conn_auth(tcp_socket_client)while True:datainput(: ).strip()if not data:continueif data quit:breaktcp_socket_client.sendall(data.encode(utf-8))responetcp_socket_client.recv(bufsize)print(respone.decode(utf-8))tcp_socket_client.close()if __name__ __main__:ip_port(127.0.0.1,9999)bufsize1024client_handler(ip_port,bufsize) 客户端(非法:不知道secret_key) 2.19 socketserver实现并发 解读socketserver源码http://www.cnblogs.com/Eva-J/p/5081851.html 2.19.1 server端 ########################### server端#####################import socketserverclass Myserver(socketserver.BaseRequestHandler):def handle(self):self.data self.request.recv(1024).strip()print({} wrote:.format(self.client_address[0]))print(self.data)self.request.sendall(self.data.upper())if __name__ __main__:HOST, PORT 127.0.0.1, 9999# 设置allow_reuse_address允许服务器重用地址
socketserver.TCPServer.allow_reuse_address True# 创建一个server, 将服务地址绑定到127.0.0.1:9999
server socketserver.TCPServer((HOST, PORT),Myserver)# 让server永远运行下去除非强制停止程序
server.serve_forever() server端 2.19.2 client端 ################################# client端#######################import socketHOST, PORT 127.0.0.1, 9999data hello# 创建一个socket链接SOCK_STREAM代表使用TCP协议with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:sock.connect((HOST, PORT)) # 链接到客户端
sock.sendall(bytes(data \n, utf-8)) # 向服务端发送数据
received str(sock.recv(1024), utf-8)# 从服务端接收数据print(Sent: {}.format(data))print(Received: {}.format(received)) client端 2.19.3 FtpServer ###########################FtpServer####################import socketserverimport structimport jsonimport osclass FtpServer(socketserver.BaseRequestHandler):codingutf-8server_dirfile_uploadmax_packet_size1024BASE_DIRos.path.dirname(os.path.abspath(__file__))def handle(self):print(self.request)while True:dataself.request.recv(4)data_lenstruct.unpack(i,data)[0]head_jsonself.request.recv(data_len).decode(self.coding)head_dicjson.loads(head_json)# print(head_dic)
cmdhead_dic[cmd]if hasattr(self,cmd):funcgetattr(self,cmd)func(head_dic)def put(self,args):file_path os.path.normpath(os.path.join(self.BASE_DIR,self.server_dir,args[filename]))filesize args[filesize]recv_size 0print(-----, file_path)with open(file_path, wb) as f:while recv_size filesize:recv_data self.request.recv(self.max_packet_size)f.write(recv_data)recv_size len(recv_data)print(recvsize:%s filesize:%s % (recv_size, filesize))ftpserversocketserver.ThreadingTCPServer((127.0.0.1,8080),FtpServer)ftpserver.serve_forever() FtpServer 2.19.4 FtpClient ########################### FtpClient########################import socketimport structimport jsonimport osclass MYTCPClient:address_family socket.AF_INETsocket_type socket.SOCK_STREAMallow_reuse_address Falsemax_packet_size 8192codingutf-8request_queue_size 5def __init__(self, server_address, connectTrue):self.server_addressserver_addressself.socket socket.socket(self.address_family,self.socket_type)if connect:try:self.client_connect()except:self.client_close()raisedef client_connect(self):self.socket.connect(self.server_address)def client_close(self):self.socket.close()def run(self):while True:inpinput(: ).strip()if not inp:continuelinp.split()cmdl[0]if hasattr(self,cmd):funcgetattr(self,cmd)func(l)def put(self,args):cmdargs[0]filenameargs[1]if not os.path.isfile(filename):print(file:%s is not exists %filename)returnelse:filesizeos.path.getsize(filename)head_dic{cmd:cmd,filename:os.path.basename(filename),filesize:filesize}print(head_dic)head_jsonjson.dumps(head_dic)head_json_bytesbytes(head_json,encodingself.coding)head_structstruct.pack(i,len(head_json_bytes))self.socket.send(head_struct)self.socket.send(head_json_bytes)send_size0with open(filename,rb) as f:for line in f:self.socket.send(line)send_sizelen(line)print(send_size)else:print(upload successful)clientMYTCPClient((127.0.0.1,8080))client.run() FtpClient 第3章 作业 转载于:https://www.cnblogs.com/maojiong/p/8376496.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/90796.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!