首页 > 编程语言 >day8(老男孩-Python3.5-S14期全栈开发)

day8(老男孩-Python3.5-S14期全栈开发)

时间:2024-04-12 10:57:05浏览次数:50  
标签:utf socket day8 server Python3.5 client print S14 data

作者:赵俊            发布日期:2020/09/15

三、Socket实现简单的ssh客户端

1、os.system和os.popen的区别

  os.system     返回值是脚本的退出状态码,只有0,1,2三种状态,直接输出命令结果在控制台

  os.popen      返回值是一个内存地址,需要用read()方法取出返回值

  print(os.system("dir"))
  print(os.popen("ipconfig").read())

2、注意

   服务器端绑定IP和端口,客户端连接IP和端口,传递的参数为元祖(“localhost”,9999),容易忽略少个括号

3、代码

  服务器端

 1 # Author:ZHJ
 2 import socket
 3 import os
 4 
 5 server = socket.socket()
 6 server.bind(("localhost",9999))
 7 server.listen(10)
 8 
 9 # print(server.accept())
10 while True:
11 
12     conn, add = server.accept()
13     # print(add)
14     print("%s:%s连接服务器" % (add[0],add[1]))
15     while True:
16 
17         data = conn.recv(1024)
18         if not data:
19             print("%s:%s断开服务器连接" % (add[0],add[1]))
20             break
21         cmd_data = os.popen(data.decode("utf-8")).read()
22         print(len(cmd_data))
23         if not cmd_data:
24             conn.send("指令错误".encode("utf-8"))
25         else:
26             conn.send(cmd_data.encode("utf-8"))

  客户端

 1 # Author:ZHJ
 2 import socket
 3 
 4 client = socket.socket()
 5 client.connect(("localhost",9999))
 6 while True:
 7 
 8     data = input(">>")
 9     if len(data) == 0:
10         continue
11     client.send(data.encode("utf-8"))
12 
13     print(client.recv(512).decode("utf-8"))

这样有一个问题需要解决

  在客户端缓冲区比较小时,服务器返回的数据大于客户端接收缓冲区,这就造成返回的数据不能一次性接收完毕,导致下一次命令执行时,返回的是上一次命令剩余的数据

四、Socket实现简单的ssh服务端(解决数据缓冲区不足以接收数据)

 解决缓冲区小不足以接收全部数据的方法:

  服务器发送数据时,把要发送数据的大小也发给客户端,然后客户端比较实际接收大小和总大小的差额来决定是否退出接收循环

期间有一个坑,需要注意↓

  在比较长度大小时,必须都是编码过得bytes型,或者解码的str型(因为同样的数据,bytes型和str型长度是不一样的)

 len()——返回对象的长度(元素个数)

 例如下:

>>> len("前")
1
>>> len("前".encode("utf-8"))
3
>>>

 解决方法的具体代码

服务器端

 1 # Author:ZHJ
 2 import socket
 3 import os
 4 
 5 server = socket.socket()
 6 server.bind(("localhost",9999))
 7 server.listen(10)
 8 
 9 # print(server.accept())
10 while True:
11 
12     conn, add = server.accept()
13     # print(add)
14     print("%s:%s连接服务器" % (add[0],add[1]))
15     while True:
16 
17         data = conn.recv(1024)
18         if not data:
19             print("%s:%s断开服务器连接" % (add[0],add[1]))
20             break
21         cmd_data = os.popen(data.decode("utf-8")).read()
22         # print(len(cmd_data))
23         #服务器端增加发送返回结果的大小(建议计算“字节”的大小)
24         #步骤-先把返回数据变成字节-取字节长度-把整型长度变成字符串-把长度字符串变成字节发送
25         conn.send(str(len(cmd_data.encode("utf-8"))).encode("utf-8"))
26         if not cmd_data:
27             conn.send("指令错误".encode("utf-8"))
28         else:
29             conn.send(cmd_data.encode("utf-8"))

客户端

 1 # Author:ZHJ
 2 import socket
 3 
 4 client = socket.socket()
 5 client.connect(("localhost",9999))
 6 while True:
 7 
 8     data = input(">>")
 9     if len(data) == 0:
10         continue
11     client.send(data.encode("utf-8"))
12     # 客户端先接受总大小,然后转成整型数字,以便比较大小
13     cmd_total_size = int(client.recv(512).decode("utf-8"))
14     print(cmd_total_size)
15     cmd_res_size = 0 # 实际接收数据大小
16     rev_data = b"" #接收数据存储
17     while cmd_res_size < cmd_total_size:
18         rev_data += client.recv(512)
19         cmd_res_size = len(rev_data)#接收数据的 长度赋值给cmd_res_size,以便每次循环比较大小
20     print(rev_data.decode("utf-8"))

五、鸡汤

 略

六、Socket粘包1

 粘包的问题解决思路,服务器给客户端发送完大小,客户端发送一个确认指令,服务器接收这个指令(可以不做任何处理)再发送有效数据,这样可以把上下两条发送分隔开

七、Socket 编程FTP 文件传输

 服务器

 1 # Author:ZHJ
 2 import socket
 3 import os
 4 
 5 server = socket.socket()
 6 server.bind(("localhost",9999))
 7 server.listen(10)
 8 
 9 # print(server.accept())
10 while True:
11 
12     conn, add = server.accept()
13     # print(add)
14     print("%s:%s连接服务器" % (add[0],add[1]))
15     while True:
16 
17         fileName = conn.recv(1024)
18         if not fileName:
19             print("%s:%s断开服务器连接" % (add[0],add[1]))
20             break
21         if os.path.isfile(fileName.decode("utf-8")):
22             f = open(fileName,"rb")
23             fileSize = os.stat(fileName).st_size
24             print(fileSize)
25             conn.send(str(fileSize).encode("utf-8"))
26             print("来自客户端:%s" % conn.recv(1024).decode("utf-8"))
27             conn.send(f.read())
28             f.close()

客户端

 1 # Author:ZHJ
 2 import socket
 3 
 4 client = socket.socket()
 5 client.connect(("localhost",9999))
 6 while True:
 7 
 8     fileName = input(">>")
 9     if len(fileName) == 0:
10         continue
11     client.send(fileName.encode("utf-8"))
12     # 客户端先接受总大小,然后转成整型数字,以便比较大小
13     file_total_size = int(client.recv(512).decode("utf-8"))
14     client.send("我已经收到文件大小,请发文件".encode("utf-8"))
15     print(file_total_size)
16     file_rev_size = 0 # 实际接收数据大小
17     rev_data = b"" #接收数据存储
18     f = open(fileName.split(".")[0] + "副本."+ fileName.split(".")[1], "wb")
19     while file_rev_size < file_total_size:
20         rev_data = client.recv(512)
21         f.write(rev_data)
22         file_rev_size += len(rev_data)#接收数据的 长度赋值给cmd_res_size,以便每次循环比较大小
23     else:
24         print("done")
25     f.close()

八、Socket粘包深入编码(内涵进度条编写)

1、进度条的编写 

  利用这个语句   sys.stdout.write("我和我的祖国"),这个语句输出没有换行,如果在写的字符串前加\r(回车符),那么光标会退到行首写,会覆盖原来的输出

2、又一个坑,前面把文件迭代了,后面再读文件,读不出来,因为迭代后光标到最末尾了

3、发送和接收交替进行可以避免粘包(往往循环时,不知道什么时候结束,还得用发送总大小来判断是否发送完毕)

带有MD5的代码

服务器

 1 # Author:ZHJ
 2 import socket
 3 import os
 4 import hashlib
 5 server = socket.socket()
 6 server.bind(("localhost",9999))
 7 server.listen(10)
 8 
 9 # print(server.accept())
10 while True:
11 
12     conn, add = server.accept()
13     # print(add)
14     print("%s:%s连接服务器" % (add[0],add[1]))
15     while True:
16 
17         fileName = conn.recv(1024)
18         if not fileName:
19             print("%s:%s断开服务器连接" % (add[0],add[1]))
20             break
21         if os.path.isfile(fileName.decode("utf-8")):
22             f = open(fileName,"rb")
23             fileSize = os.stat(fileName).st_size
24             print(fileSize)
25             conn.send(str(fileSize).encode("utf-8"))
26             print("来自客户端:%s" % conn.recv(1024).decode("utf-8"))
27             m = hashlib.md5()
28             for line in f:
29                 m.update(line)
30                 # print(len(line))
31                 con = conn.send(line)
32                 # print(con)
33             conn.recv(1024)# 可以避免粘包
34             f.close()
35             print(m.hexdigest())
36             conn.send(m.hexdigest().encode())

客户端

 1 # Author:ZHJ
 2 import socket
 3 import hashlib
 4 import sys
 5 client = socket.socket()
 6 client.connect(("localhost",9999))
 7 while True:
 8 
 9     fileName = input(">>")
10     if len(fileName) == 0:
11         continue
12     client.send(fileName.encode("utf-8"))
13     # 客户端先接受总大小,然后转成整型数字,以便比较大小
14     file_total_size = int(client.recv(512).decode("utf-8"))
15     client.send("我已经收到文件大小,请发文件".encode("utf-8"))
16     print(file_total_size)
17     file_rev_size = 0 # 实际接收数据大小
18     rev_data = b"" #接收数据存储
19     f = open(fileName.split(".")[0] + "副本."+ fileName.split(".")[1], "wb")
20     m = hashlib.md5()
21     while file_rev_size < file_total_size:
22         rev_data = client.recv(1024)
23         # print("每次接收的大小:%s"%len(rev_data))
24         f.write(rev_data)
25         m.update(rev_data)
26         file_rev_size += len(rev_data)#接收数据的 长度赋值给cmd_res_size,以便每次循环比较大小
27         # print("接收的总大小:%s" % file_rev_size)
28         bar = int((file_rev_size/file_total_size)*100)#进度百分比
29         sys.stdout.write("\r"+int(bar/5)*"■"+"%s%%"%bar)#进度条显示
30 
31     else:
32         print("")
33         print("done")
34         client.send(b"ok")# 可以避免粘包
35         rev_md5 = client.recv(512).decode("utf-8")
36         print("源文件的md5:%s" % rev_md5)
37         print("接收文件的md5:%s" % m.hexdigest())
38     f.close()

 

九、SocketServer

1、socketserver 提供多用户也就是并发功能,其实就是对socket的一个封装,使其更简单

2、分为几种类型

  class socketserver.TCPServer(server_addressRequestHandlerClassbind_and_activate=True)

  class socketserver.UDPServer(server_addressRequestHandlerClassbind_and_activate=True)

  底下两个不常用

  class socketserver.UnixStreamServer(server_addressRequestHandlerClassbind_and_activate=True)

  class socketserver.UnixDatagramServer(server_addressRequestHandlerClass,bind_and_activate=True)

3、创建一个socketServer需要以下几步

  1、你必须 自己创建一个请求处理类,并继承BaseRequestHandler类,还要重写父类的handle()方法,和客户端所有的交互都在handle里完成

  2、必须实例化一个TCPServer或UDPServer,并传递ip和上面创建的请求处理类给这个TCPServer或UDPServer

  3、实例.handle_request()(只处理一个请求)或者 实例.server_forever(poll_interval=0.5)(处理多个请求,参数意思每0.5秒检测一次关闭请求)

  4、实例.server_close()关闭套接字

简单的socketserver代码实例

服务器

 1 # Author:ZHJ
 2 # import socketserver
 3 from socketserver import *
 4 
 5 
 6 class MyRequest(BaseRequestHandler):
 7     def handle(self):
 8         while True:
 9             self.data = self.request.recv(1024).strip()
10             if not self.data:
11                 print("客户端断开")
12                 break
13             print(self.data)
14             self.request.send(self.data.upper())
15 
16 server = TCPServer(("localhost",9999), MyRequest)
17 server.serve_forever()
18 server.close_request()

客户端

 1 client = socket.socket()# 创建一个socket对象
 2 client.connect(("localhost",9999))# 连接指定ip和端口
 3 while True:
 4     da = input("send>>>")
 5     if len(da) == 0:#不能send空字符
 6         continue
 7     client.send(da.encode("utf-8"))
 8     # print("\033[1;31msend:%s\033[0m" % da)
 9     data = client.recv(1024)
10     print("\033[1;32mrecv:%s\033[0m" % str(data,encoding="utf-8"))
11 client.close()

十、SocketServer多并发

 实例化时使用ThreadingTCPServer就可以多线程实现多并发

 实例化时使用ForkingingTCPServer就可以多进程实现多并发(windows上用不了,在windows上无法使用fork创建新进程,linux上可以)

例:server = ThreadingTCPServer(("localhost",9999), MyRequest)

十一、作业,多用户在线FTP程序

开发一个支持多用户在线的FPT程序

要求:

  1、用户加密认证

  2、允许同时多用户登录

  3、每个用户有自己的家目录,且只能访问自己的家目录

  4、对用户进行磁盘配额,每个用户的可用空间不同

  5、允许用户在FTPserver上随意切换目录

  6、允许用户查看当前目录下文件

  7、允许用户上传和下载文件,保证文件一致性

  8、文件传输过程中显示进度条

  9、附加功能,支持文件的断点续传

标签:utf,socket,day8,server,Python3.5,client,print,S14,data
From: https://www.cnblogs.com/zhao-jun/p/13758392.html

相关文章

  • JAVA语言学习-Day8
    参考教学视频:秦疆GUI组件:窗口、弹框、面板、文本框、列表框、按钮、图片、监听事件、鼠标、键盘事件、破解工具1.简介Gui的核心:SwingAWT界面不美观需要jre环境2.AWTawt介绍:包含了很多的接口和类元素:窗口、按钮、文本框java.awt.*组件Componentbu......
  • 就业班 第二阶段 2401--3.28 day8 shell之循环控制
    七、shell编程-循环结构shell循环-for语句foriin{取值范围}  #for关键字i变量名in关键字取值范围格式12345do          #do循环体的开始循环体done         #done循环体的结束#!/usr/......
  • kerberos-MS14-068(kerberos域用户提权)
    微软官方在2014年11月18日发布了一个紧急补丁,Windows全版本服务器系统受到影响,包括WindowsServer2003,WindowsServer2008,WindowsServer2008R2,WindowsServer2012和WindowsServer2012R2,修复了MicrosoftWindowsKerberosKDC(CVE-2014-6324),该漏洞可导致活动目录整体权......
  • LeetCode刷题记录——day8
    https://leetcode.cn/problems/spiral-matrix/description/?envType=study-plan-v2&envId=2024-spring-sprint-100注意每次改变边界都有判断一次classSolution{public:vector<int>spiralOrder(vector<vector<int>>&matrix){vector<int&g......
  • Honeywell 8LS14C
    传感器是一种可感知物理量或物体特征并将其转化为可用于测量、监测、控制等目的的信号的设备。传感器通过感知外部环境的物理量或物体特征,将其转换为电信号或其他形式的信号输出,以便进行相关的测量、控制和判断。常见的传感器包括温度传感器、压力传感器、光敏传感器、声音......
  • Linux学习-day8
    vim的使用安装vimyuminstallvim-y验证是否有vimvim的使用基本上vi/vim共分为三种模式,分别是:命令模式(Commandmode)最长用的,按下字母,a,i,o(a在光标前开始编辑,i是在光标处,开始编辑,o是在光标下一行开始编辑)当你使用vim标记某个文件时,第一步就进入了命令模式。你此......
  • VMware安装MacOS14(Sonoma)
    如果你想在Windows电脑上体验苹果最新的macOS14Sonoma系统!那么跟着我步骤来进行安装吧~安装步骤:1、首先下载并安装VMWare虚拟机软件【官网下载】下载【VMWareUnlocker】,以管理员身份运行win-install3.下载macOS14索诺玛(Sonoma)的ISO系统文件【点击下载】......
  • CS144_2020_Fall_lab1(流重组)
    废话已经在lab0说完了,我们直接来看lab10一些规定,废话1概述在实验0中,你使用了一个互联网流套接字来从网站获取信息并发送电子邮件,使用了Linux内置的传输控制协议(TCP)实现。这个TCP实现成功地产生了一对可靠的按顺序的字节流(一个从你到服务器的流,另一个在相反的方向),即使底层......
  • CS144_2020_Fall_lab0(实现开始,准备工作)
    碎碎念开头:三年竞赛无人问,一朝面试全盘输,大三的寒假过的并不是那么舒服,准备春招实习,筹备项目,面对满纸漏洞的简历,决定去做一下这个闻名已久的计算机网络实验:CS144-基于UDP实现TCP。虽说已经做完了,但是对于其中一些知识点扔不是很牢固,有些测试点仅仅也是面向样例编程,不明所以,仅以此......
  • macOS14使用brew下载Redis时出现的问题和解决方法
    当我使用brew下载redis时系统:macOS14(base)hanxuxian@hanxuxiandeMacBook-Air~%brewinstallredis报错信息:Error:git:unknownorunsupportedmacOSversion::dunnoError:'git'mustbeinstalledandinyourPATH!Warning:YouareusingmacOS14.Wedon......