python之day9(socket)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python之day9(socket)相关的知识,希望对你有一定的参考价值。
今日重点socket网络编程:
1,tcp/ip简介:
2,socket简单应用模型:
3,socket单用户模式扩展:
4,socketserver实例:
首先记录一个在day6时没有记录的知识点:
百分比的应用:
import sys import time def view_bar(num, total): rate = float(num) / float(total) rate_num = int(rate * 100) r = ‘\\r%d%%‘ % (rate_num, ) sys.stdout.write(r) sys.stdout.flush() if __name__ == ‘__main__‘: for i in range(0, 101): time.sleep(0.1) view_bar(i, 100)
进入主要内容:
一,tcp/ip
osi7层结构以及具体作用。
物理层:电缆,双绞线,无线电波
链路层(网卡):ethernet通用协议---》找到唯一的mac地址
网络层:IP 找到了子网中唯一的标识。
传输层:tcp,udp,port 规定传输协议以及端口号。
tcp/ip基本模型
二,socket简单应用模型:
socket的所在位置。
整个的socket交流过程。
socket要点提示:
1.基于python3.5.2版本的socket只能收发字节(python2.7可以发送str)
2.退出只在客户端退出就ok了
3.s.accept()和s.recv()是阻塞的(基于链接正常)
4.listen(n) n代表:能挂起的链接数,如果n=1,代表可以链接一个,挂起一个,第三个拒绝
5.服务端出现端口冲突:修改监听端口号
6.服户端:1.send #数据长度
4.recv #收到确认信息,开始下一步发送
send
客户端:2.recv #获取数据长度
3.send #发送确认信息
recv #循环接收
基础socket程序:
1 import socket 2 ip_port=(‘127.0.0.1‘,9999) 3 #买手机 4 s=socket.socket() 5 #买手机卡 6 s.bind(ip_port) 7 #开机 8 s.listen(5) 9 #等待电话 10 while True: 11 conn,addr=s.accept() 12 #收消息 13 while True: 14 try: 15 recv_data=conn.recv(1024) 16 if len(recv_data) == 0:break 17 # print(‘--------------------‘,type(recv_data)) 18 #发消息 19 send_data=recv_data.upper() 20 print(send_data) 21 conn.send(send_data) 22 except Exception: 23 break 24 #挂电话t 25 conn.close()
1 #!/usr/bin/env python 2 # -*- coding: UTF-8 -*- 3 # Author: Aaron Shen 4 5 import socket 6 ip_port=(‘127.0.0.1‘,9999) 7 #买手机 8 s=socket.socket() 9 #拨号 10 s.connect(ip_port) 11 #发送消息 12 while True: 13 send_data=input(">>: ").strip() 14 if send_data == "exit": break 15 if len(send_data) == 0:continue 16 s.send(bytes(send_data,encoding=‘utf8‘)) 17 18 19 #收消息 20 recv_data=s.recv(1024) 21 print(str(recv_data,encoding=‘utf8‘)) 22 #挂电话 23 s.close()
三,socket单用户模式扩展:
关于执行系统命令,以及粘包问题解决思想:
执行系统命令 用到subprocess 模块 .Popen方法 参数跟(系统命令,shell=True,stdout = subprocess.PIPE, stderr = subprocess.PIPE)
粘包问题产生的原因:
由于发送端的字节数超过了接收端一次性可接收的数量,到时一次无法将发送端的数据全部接收完,再继续执行命令是会继续进行发送,造成粘包。
解决办法:
首先就是要有一下循环的思想,只要没接收完就一直接收。因此我们要知道发送包data的具体大小。
其次我们要先将data的大小发送给接收端。
然后接收端回复Ok我收到了发送端要发送多大的包给我,我会根据这个包的大小进行循环接收,接收完就不再接收。
最后发送端开始发送数据,接收端接收知道接收完成。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Alex Lire 4 import socket 5 import subprocess #导入执行命令模块 6 ip_port=(‘127.0.0.1‘,9999) #定义元祖 7 #买手机 8 s=socket.socket() #绑定协议,生成套接字 9 s.bind(ip_port) #绑定ip+协议+端口:用来唯一标识一个进程,ip_port必须是元组格式 10 s.listen(5) #定义最大可以挂起胡链接数 11 #等待电话 12 while True: #用来重复接收新的链接 13 conn,addr=s.accept() #接收客户端胡链接请求,返回conn(相当于一个特定胡链接),addr是客户端ip+port 14 #收消息 15 while True: #用来基于一个链接重复收发消息 16 try: #捕捉客户端异常关闭(ctrl+c) 17 recv_data=conn.recv(1024) #收消息,阻塞 18 if len(recv_data) == 0:break #客户端如果退出,服务端将收到空消息,退出 19 20 #发消息 21 p=subprocess.Popen(str(recv_data,encoding=‘utf8‘),shell=True,stdout=subprocess.PIPE) #执行系统命令,windows平 22 # 台命令的标准输出是gbk编码,需要转换 23 res=p.stdout.read() #获取标准输出 24 if len(res) == 0: #执行错误命令,标准输出为空, 25 send_data=‘cmd err‘ 26 else: 27 send_data=str(res,encoding=‘gbk‘) #命令执行ok,字节gbk---->str---->字节utf-8 28 29 send_data=bytes(send_data,encoding=‘utf8‘) 30 31 32 #解决粘包问题 33 ready_tag=‘Ready|%s‘ %len(send_data) 34 conn.send(bytes(ready_tag,encoding=‘utf8‘)) #发送数据长度 35 feedback=conn.recv(1024) #接收确认信息 36 feedback=str(feedback,encoding=‘utf8‘) 37 38 if feedback.startswith(‘Start‘): 39 conn.send(send_data) #发送命令的执行结果 40 except Exception: 41 break 42 #挂电话 43 conn.close()
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Alex Li 4 import socket 5 ip_port=(‘127.0.0.1‘,9999) 6 #买手机 7 s=socket.socket() 8 #拨号 9 s.connect(ip_port) #链接服务端,如果服务已经存在一个好的连接,那么挂起 10 11 while True: #基于connect建立的连接来循环发送消息 12 send_data=input(">>: ").strip() 13 if send_data == ‘exit‘:break 14 if len(send_data) == 0:continue 15 s.send(bytes(send_data,encoding=‘utf8‘)) 16 17 #解决粘包问题 18 ready_tag=s.recv(1024) #收取带数据长度的字节:Ready|9998 19 ready_tag=str(ready_tag,encoding=‘utf8‘) 20 if ready_tag.startswith(‘Ready‘):#Ready|9998 21 msg_size=int(ready_tag.split(‘|‘)[-1]) #获取待接收数据长度 22 start_tag=‘Start‘ 23 s.send(bytes(start_tag,encoding=‘utf8‘)) #发送确认信息 24 25 #基于已经收到的待接收数据长度,循环接收数据 26 recv_size=0 27 recv_msg=b‘‘ 28 while recv_size < msg_size: 29 recv_data=s.recv(1024) 30 recv_msg+=recv_data 31 recv_size+=len(recv_data) 32 print(‘MSG SIZE %s RECE SIZE %s‘ %(msg_size,recv_size)) 33 34 print(str(recv_msg,encoding=‘utf8‘)) 35 #挂电话 36 s.close()
四,socketserver实例:
这部分是alex大拿老师讲的,基本上没听懂,呵呵,主要靠课下重新读代码,重新构思的。
首先说一下socketserver与普通socket的区别:
普通socket所有点链路(conn)都是单通道的,只能一个客户端占用。服务端也是一对一进行相应。如果还有别的客户端要访问就要排队等待,直到之前的客户端退出后才可以与服务端进行交互。
socketserver 使用socketserver模块(2.7头字母要进行大写),继承了socketserver.BaseRequestHandler这个类,我们用的时候必须使用 handle这个函数。他的特点就是可以完成一对多的相应。
基本程序构建:
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Alex Li 4 5 6 #!/usr/bin/env python 7 # -*- coding:utf-8 -*- 8 #import SocketServer 9 import socketserver 10 11 class MyServer(socketserver.BaseRequestHandler): 12 def handle(self): 13 # print self.request,self.client_address,self.server 14 self.request.sendall(bytes(‘欢迎致电 10086,请输入1xxx,0转人工服务.‘,encoding="utf-8")) 15 while True: 16 data = self.request.recv(1024) 17 print("-->",len(data)) 18 if len(data) == 0:break 19 print("[%s] says:%s" % (self.client_address,data.decode() )) 20 self.request.sendall(data.upper()) 21 22 if __name__ == ‘__main__‘: 23 server = socketserver.ThreadingTCPServer((‘127.0.0.1‘,8009),MyServer) 24 server.serve_forever()
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Alex Li 4 5 import socket 6 ip_port=(‘192.168.11.58‘,8009) 7 #买手机 8 s=socket.socket() 9 #拨号 10 s.connect(ip_port) 11 #发送消息 12 welcome_msg = s.recv(1024) 13 print("from server:",welcome_msg.decode()) 14 while True: 15 send_data=input(">>: ").strip() 16 if len(send_data) == 0:continue 17 s.send(bytes(send_data,encoding=‘utf8‘)) 18 #收消息 19 recv_data=s.recv(1024) 20 print(str(recv_data,encoding=‘utf8‘)) 21 #挂电话 22 s.close()
通过socket 远程执行命令(通过客户端发送命令到服务端并执行)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Alex Li 4 5 6 #!/usr/bin/env python 7 # -*- coding:utf-8 -*- 8 #import SocketServer 9 import socketserver 10 import subprocess 11 class MyServer(socketserver.BaseRequestHandler): 12 def handle(self): 13 # print self.request,self.client_address,self.server 14 self.request.sendall(bytes(‘欢迎致电 10086,请输入1xxx,0转人工服务.‘,encoding="utf-8")) 15 while True: 16 data = self.request.recv(1024) 17 if len(data) == 0:break 18 print("[%s] says:%s" % (self.client_address,data.decode() )) 19 #self.request.sendall(data.upper()) 20 cmd = subprocess.Popen(data.decode(),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) 21 cmd_res =cmd.stdout.read() 22 if not cmd_res: 23 cmd_res = cmd.stderr.read() 24 if len(cmd_res) == 0: #cmd has not output 25 cmd_res = bytes("cmd has output",encoding="utf-8") 26 self.request.send(cmd_res ) 27 28 29 if __name__ == ‘__main__‘: 30 server = socketserver.ThreadingTCPServer((‘0.0.0.0‘,8009),MyServer) 31 server.serve_forever()
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Alex Li 4 5 import socket 6 ip_port=(‘192.168.11.58‘,8009) 7 #买手机 8 s=socket.socket() 9 #拨号 10 s.connect(ip_port) 11 #发送消息 12 welcome_msg = s.recv(1024) 13 print("from server:",welcome_msg.decode()) 14 while True: 15 send_data=input(">>: ").strip() 16 if len(send_data) == 0:continue 17 s.send(bytes(send_data,encoding=‘utf8‘)) 18 #收消息 19 recv_data=s.recv(1024) 20 print(str(recv_data,encoding=‘utf8‘)) 21 #挂电话 22 s.close()
通过socket进行ftp 上传操作(通过客户端发送指令,上传到服务器端)
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Alex Li 4 5 6 #!/usr/bin/env python 7 # -*- coding:utf-8 -*- 8 #import SocketServer 9 import socketserver,json 10 class MyServer(socketserver.BaseRequestHandler): 11 def handle(self): 12 # print self.request,self.client_address,self.server 13 self.request.sendall(bytes(‘欢迎致电 10086,请输入1xxx,0转人工服务.‘,encoding="utf-8")) 14 while True: 15 data = self.request.recv(1024) #接收要进行操作的基本信息,包括动作,文件路径以及文件名,文件大小 16 if len(data) == 0:break 17 print("data", data) 18 print("[%s] says:%s" % (self.client_address,data.decode() )) 19 20 task_data = json.loads( data.decode() ) #接收到一个json格式的字典 21 task_action = task_data.get("action") #获取字典的中动作的值 22 if hasattr(self, "task_%s"%task_action): #反射到本程序的下面的函数,查看是否存在。如果存在 23 func = getattr(self,"task_%s" %task_action) #获取函数 24 func(task_data) #执行函数,同时参数就是那个字典 25 else: 26 print("task action is not supported",task_action) 27 28 def task_put(self,*args,**kwargs): 29 print("---put",args,kwargs) 30 filename = args[0].get(‘filename‘) #文件名就等于task_data.get(‘filename‘) 31 filesize = args[0].get(‘file_size‘) #文件大小就等于task_data.get(‘file_size‘) 32 server_response = {"status":200} #准备工作都准备好后,给客户端发一个确认 33 self.request.send(bytes( json.dumps(server_response), encoding=‘utf-8‘ )) #发送确认 34 f = open(filename,‘wb‘) #打开文件 35 recv_size = 0 #未开始接收,因此接收大小是 0 36 while recv_size < filesize: #如果接收大小小于文件大小就是一直循环 37 data = self.request.recv(4096) #开始接收 38 f.write(data) #写入文件 39 recv_size += len(data) #增加大小 40 print(‘filesize: %s recvsize:%s‘ % (filesize,recv_size)) #展示进度 41 print("file recv success") #循环结束,完成接收 42 f.close() 43 44 if __name__ == ‘__main__‘: 45 server = socketserver.ThreadingTCPServer((‘0.0.0.0‘,8009),MyServer) 46 server.serve_forever()
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Alex Li 4 5 import socket 6 import os ,json 7 ip_port=(‘192.168.11.150‘,8009) #要访问的服务端IP以及端口 8 #买手机 9 s=socket.socket() #生成套接字s 10 #拨号 11 s.connect(ip_port) #连接服务和端口 12 #发送消息 13 welcome_msg = s.recv(1024) #获取服务端相应 14 print("from server:",welcome_msg.decode()) #打印获取的服务端欢迎语 15 while True: #循环交互 16 send_data=input(">>: ").strip() 17 if len(send_data) == 0:continue #如果发送为空就重新发送 18 19 cmd_list = send_data.split() #将命令进行分割 [put test.txt] 20 if len(cmd_list) <2:continue #如果小于2个元素就重新输入,命令是不完整的 21 task_type = cmd_list[0] #第一个是命令 put, 第二个是文件路径 22 if task_type == ‘put‘: #如果是 put 23 abs_filepath = cmd_list[1] #第二个就是文件路径 24 if os.path.isfile(abs_filepath): #如果文件存在 25 file_size = os.stat(abs_filepath).st_size #获取文件大小 26 filename = abs_filepath.split("\\\\")[-1] #获取文件名 27 print(‘file:%s size:%s‘ %(abs_filepath,file_size)) 28 msg_data = {"action":"put", 29 "filename":filename, 30 "file_size":file_size} #写成字典包括动作,文件名,文件大小 31 32 s.send( bytes(json.dumps(msg_data),encoding="utf-8") ) #将字典整合成json发送给服务端(明确要上传的信息) 33 server_confirmation_msg = s.recv(1024) #接收服务端发送的确认信息。 34 confirm_data = json.loads(server_confirmation_msg.decode()) #获取确认信息,服务端发来的信息也是json封装的字典 35 if confirm_data[‘status‘] ==200: #如果是200 确认成功 36 37 print("start sending file ",filename) 38 f = open(abs_filepath,‘rb‘) #二进制打开要上传的文件 39 for line in f: #逐行循环 40 s.send(line) #上传到服务端 41 42 print("send file done ") 43 44 else: 45 print("\\033[31;1mfile [%s] is not exist\\033[0m" % abs_filepath) 46 continue 47 else: 48 print("doesn‘t support task type",task_type) 49 continue 50 #s.send(bytes(send_data,encoding=‘utf8‘))
以上是关于python之day9(socket)的主要内容,如果未能解决你的问题,请参考以下文章