本节主要讲解socket编程的有关知识点,顺便也会讲解一些其它的关联性知识:

一、概述(socket、socketserver):

python对于socket编程,提供了两个模块,分别是socket和socketserver,它们之间最大的区别在于,socketserver能轻松的实现并发访问,关于这个后面都会介绍的。

先说socket的编程思路:

1 #客户端创建socket并连接服务器

2 s =socket.socket()3 ip_port = ('127.0.0.1',8089)4 s.connect(ip_port)5

6 ----------------------------------

7 #服务端创建socket并等待客户端的连接

8 s =socket.socket()9 ip_port = ('127.0.0.1',8089)10 s.bind(ip_port)11 s.listen(5)12 conn,client_address = s.accept()

下面根据上面的代码做一个简单的介绍:

i. 首先我们先看客户端代码的意思(前提是先在第一行的上面导入socket模块,import socket),第一行创建一个socket对象,对于客户端来说,只要知道服务端的IP和 端口,就可以直接连接了,也就是调用connect()方法就可以了。

ii. 那么我们再来看服务端的代码,第一行也是先生成一个socket对象(在这里插入一句以前讲过的知识点,那就是方法只能通过对象去调用),然后服务端需要绑定一个IP和端口(调用bind方法实现),供客户端去连接,然后调用listen

方法,listen方法的作用是定义坚挺客户端的数量;调用accept方法才是允许客户端连接的额最后一步,它会返回一个连接的对象conn,还会返回客户端的IP地址。

iii. 这样我们就建立了客户端到服务端的初步连接,下面我们要谈的,就是连接是建立起来了,那怎么样传输数据呢?我们通过下面这个实例来进一步的讲解:

1 #客户端发送字符串的代码

2 str = 'hello'

3 s.send(bytes(str,encoding='utf8'))4

5 ----------------------------------------

6

7 #服务端接收字符串的代码

8 conn,client_address =s.accept()9 recv_data = conn.recv(1024)10 print(str(recv_data,encoding='utf8'))11 print(recv_data.decode())12

13 -----------------------------------------

14

15 #输出结果

16 hello17 hello

解释说明:

1,客户端使用send方法发送一个字符串hello,服务端使用recv方法接受字符串。

2,重点说明的是python2.7版本可以直接发送字符串,但是在python3.0以上的版本都已经不支持这种功能了,改成了只发送和接受字节的形式,所以在你使用python3.0以上版本的时候,要先把字符串转换成字节,然后再发送。

3,不管是把字节转换成字符串,还是把字符串转换成字节,使用的编码都是utf8。

这就是整个发送和接收的流程,其实并不难,因为这就是一个发送和一个接受的过程,如果多的话,就显得有点乱了。

二,并发的实现:

如果你的代码跑在真正的生产环境中,那么就不可能只有一个用户去连接,其它用户都在等待的状态,显然,这是不现实的,那么怎么样才能做到并发处理呢?其实就是用我们上面提到的socketserver模块来实现并发处理的,下面看具体的事例:

client端:

1 importsocket2

3 s =socket.socket()4 ip_port = ('127.0.0.1',8089)5 s.connect(ip_port)6 str = 'hello'

7 s.send(bytes(str,encoding='utf8'))

View Code

server端:

1 importsocketserver2

3 classMyclass(socketserver.BaseRequestHandler):4 defhandle(self):5 recv_data = self.request.recv(1024)6 print(recv_data.decode())7

8 s = socketserver.ThreadingTCPServer(('127.0.0.1',8089),Myclass)9 s.serve_forever()10

11 #输出结果hello

View Code

解释说明:

客户端上的代码是一样的,我们只需要看服务端的代码就可以了;首先导入socketserver模块,然后定义一个类叫Myclass,后面括号里面的意思就是继承BaseRequestHandler这个父类,其实在这里定义类的时候,应该注意两个点:

i. 必须继承上面说的那个父类(没有为啥,只是规定)。

ii. 在类里面定义一个handle方法,这个方法是python内部定义好的,在接受客户端发送的字符串的时候,也是调用的这个方法。

然后是调用这个socketserver模块的另一个类来定义调用的自己的类,和要连接的ip和端口;最后执行s.serve_forver()这个方法(其实这个模块中的类和方法所实现的原理就是判断accept客户端的时候,是否有新的链接连接进来;

如果有新的链接进来的话,socket内部会发生变化,python就是根据这种变化,来建立一个新的连接;使用for循环的方式去接收多用户的连接。)

iii. 其实并发处理用到了两个知识点,一个是IO多路复用,一个是多线程或者多线程。

在这里额外的说一下多进程和多线程,通俗点讲就是:(应用程序---》进程---》线程),其实就是这么的一层关系,但是Python中针对不同的程序用多进程或者多线程是不一样的,比如一个程序不需要大量的运算,那么就不需要

消耗太多的CPU,那么用多线程就比较合适了;如果是计算量比较大,那么在Python中应该用多进程。

三、通过搭建一个简单的ftp服务器来深入得了解socket和其它的一些小知识:

废话不多说,直接上代码,简单明了:

client端:

1 whileTrue:2 ftp_user = input('Input Your ftp user:')3 ftp_pass = input('Input Your ftp pass:')4 s.send(bytes(ftp_user,encoding='utf8'))5 status_code = s.recv(1024)6 status_code = str(status_code,encoding='utf8')7 if status_code == '200':8 s.send(bytes(ftp_pass,encoding='utf8'))9 status_code = s.recv(2014)10 status_code = str(status_code,encoding='utf8')11 if status_code == '200':12 pass

13 else:14 print(status_code)15 continue

16 else:17 print(status_code)18 continue

19 whileTrue:20 ftp_action = input('请输入你要执行的ftp操作>>>:').strip()21 com_dict = {'help/?':'使用帮助','ls':'查看当前用户下的文件或目录','cd':'切换目录',22 'put':'上传文件','get':'下载文件','mkdir':'创建目录'}23 if ftp_action == 'q':24 sys.exit()25 if len(ftp_action) == 0:continue

26 cmd_list =ftp_action.split()27 #如果输入put 文件名,就执行put

28 if cmd_list[0] == 'put':29 abs_filepath = cmd_list[1]30 ifos.path.isfile(abs_filepath):31 file_size =os.stat(abs_filepath).st_size32 filename = abs_filepath.split('\\')[-1]33 print("file:%s,size:%s" %(abs_filepath,file_size))34 msg_data = {"action":"put","filename":filename,"file_size":file_size,"ftp_user":ftp_user}35 s.send(bytes(json.dumps(msg_data),encoding='utf8'))36 recv_data = s.recv(1024)37 status_code = json.loads(str(recv_data,encoding='utf8'))38 print(status_code)39 if status_code['status'] == 200:40 print('start send file:',filename)41 f = open(abs_filepath,'rb')42 for line inf:43 s.send(line)44 print('send file done')45 else:46 print('The file is not exist!!')

View Code

server端:

1 user_dict = json.load(open(os.path.join(settings.user_dir,'user_info')))2 classMyServer(socketserver.BaseRequestHandler):3

4 defhandle(self):5 #服务端验证客户端输入的用户名和密码

6 whileTrue:7 ftp_user = self.request.recv(1024)8 if ftp_user.decode() inuser_dict:9 self.request.send(bytes('200',encoding='utf8'))10 ftp_pass = self.request.recv(1024)11 str_ftp_pass =ftp_pass.decode()12 md =hashlib.md5(str_ftp_pass.encode()).hexdigest()13 if md == user_dict[ftp_user.decode()].get('passwd'):14 self.request.send(bytes('200',encoding='utf8'))15 current_dir = {'current_dir':'',}16 break

17 else:18 self.request.sendall(bytes('你输入的密码不正确!!',encoding='utf8'))19 continue

20 else:21 self.request.sendall(bytes('你输入的用户名不存在!!',encoding='utf8'))22 continue

23 #循环的目的是接收客户端发送的字典信息,然后判断调用不同的方法

24 whileTrue:25 data = self.request.recv(1024)26 if len(data) == 0:break

27

28 task_data =json.loads(data.decode())29 task_action = task_data.get('action')30 if hasattr(self,"task_%s"%task_action):31 func = getattr(self,"task_%s"%task_action)32 func(task_data,current_dir)33 #如果用户输入的是put命令,就调用此方法

34 def task_put(self,*args,**kwargs):35 filename = args[0].get('filename')36 file_size = args[0].get('file_size')37 user_dic = args[0].get('ftp_user')38 server_response = {"status":200}39 self.request.send(bytes(json.dumps(server_response),encoding='utf8'))40 f = open(user_dic+'\\'+filename,'wb')41 recv_size =042 while recv_size <43 data="self.request.recv(1024)44" f.write recv_size print recv sucess f.close>

View Code

我想当大家看这段代码的时候,感觉有点乱,那我就跟大家梳理一下思路,以及传输的流程:

1、首先我先给你们说下整个程序大概的一个流程,首先客户端在执行ftp命令之前,先输入用户密码,然后把用户和加密过的密码发送到服务端,让服务端的程序去判断,客户输入的用户名或密码是否正确,然后给出相应的输出;

现在客户端可以执行ftp命令了(在这里只能执行put命令),如果客户端输入的格式正确,就把文件名、文件大小和用户名传到服务端(重点说明:把文件名传过去是想要服务器知道要传的文件,文件大小的作用是为了防止文件

粘包,粘包的结果就是传输不完整(在本实例中,为了粘包是根据客户端提供的文件大小,跟接收的文件大小做判断,只要接收的文件大小小于实际大小,就会一直传输),下面我再详细的讲解粘包的概念;传输用户名的目的是让

该用户只能访问它自己的家目录)

2、我感觉你不明白的可能有两个地方,一个是在server端定义的current_dir字典,在我所列出的代码中,没有体现出来这个字典的真正用图,其实定义它的目的是为了存放每个用户的进入子目录所存的一个标示,存在字典里,然后

用户再执行ls或者mkdir命令的时候,就会从这个字典里取出用户进入的子目录做一列的操作。

3、另外一个可能是hasattr和getattr这两个内置的函数了,hasattr(self,name):这个的意思是说,self对象里面是否包含name方法,如果有,则返回True,如果没有就返回False;

func = get(self,name): 这个和上面那个相结合,就是如果存在就把这个方法或者函数赋值给func,然后由它其传参等操作。

四、附加小知识:

1、在socket客户端和服务端互传数据的时候,如果传输一串字符串很长,那么如果还是用send的话,就可能会出现传输不完全的情况,结果这一个问题的方法是把send换成sendall就OK了!!

43>

python中socket怎么用_Python 之socket的应用相关推荐

  1. python中bind的用法_Python socket.bind方法代码示例

    本文整理汇总了Python中socket.bind方法的典型用法代码示例.如果您正苦于以下问题:Python socket.bind方法的具体用法?Python socket.bind怎么用?Pyth ...

  2. python socket模块作用_python之socket模块详解--小白博客

    主要是创建一个服务端,在创建服务端的时候,主要步骤如下: 创建socket对象socket-->绑定IP地址和端口bind-->监听listen-->得到请求accept--> ...

  3. python中线程和进程_python中线程和进程的简单了解

    一.操作系统.应用程序 1.硬件:硬盘.cpu.主板.显卡........ 2.装系统(本身也是一个软件): 系统就是一个由程序员写出来的软件,该软件用于控制计算机得硬盘,让他们之间进行互相配合. 3 ...

  4. python中冒号报错_python中一些常见的错误_后端开发

    PHP8 新特性之 Attributes_后端开发 PHP8的Alpha版本,过几天就要发布了,其中包含了不少的新特性,今天呢,我想谈谈Attributes,为啥呢, 是昨天我看到很多群在转发一个文章 ...

  5. python中doc=parased.getroot()_python实例手册.py

    python实例手册 #encoding:utf8 # 设定编码-支持中文 0 说明 手册制作: 雪松 littlepy www.51reboot.com 更新日期: 2016-01-21 欢迎系统运 ...

  6. python中的元类_python中的元类

    类也是对象,但是类有创建对象的能力 动态创建一个类: classmonkey():defbanana(self):print 'banana!' defapple(self):print 'i wan ...

  7. python中chr的用法_python中chr()函数和ord()函数的用法

    原博文 2018-06-11 21:52 − 一,chr()函数 格式:Chr(<数值表达式>) 说明:函数返回值类型为String,其数值表达式值取值范围为0~255. 例如:Print ...

  8. python中csv文件操作_python中操作csv文件

    python中操作csv文件 读取csv improt csv f = csv.reader(open("文件路径","r")) for i in f: pri ...

  9. python中for循环缩进_Python减少循环层次和缩进的技巧分析

    本文实例分析了Python减少循环层次和缩进的技巧.分享给大家供大家参考,具体如下: 我们知道Python中冒号和缩进代表大括号,这样写已经可以节省很多代码行数,但是可以更优化,尽可能减少循环的层次和 ...

最新文章

  1. 【PC工具】更新win10关闭更新工具,接速度最快最好用的文件内容搜索工具:searchmyfiles...
  2. 这年头,好文案都被它承包了!
  3. ospf 环回口的路由条目_【网络工程师配置篇】——OSPF汇总配置!
  4. Spring Boot JDBC
  5. Jeecg入门篇,高手掠过
  6. 【Excel-2010】导入网站数据
  7. 变量“componentresourcemanager”未声明或从未赋值_频繁出现在面试题中,却容易被人遗忘:变量、基本数据类型...
  8. 黑莓Z10忘记BBID密码导致手机锁定解决方案
  9. 图片文字转换成word软件在线版
  10. 网口调试助手如何以服务器与plc调试,PLC调试助手
  11. 正弦定理和余弦定理_高中数学,正弦定理和余弦定理的应用举例,含高频考点及详细解析...
  12. 书籍折页是什么效果_书籍折页什么样 - 卡饭网
  13. 全国计算机考试 二级 office pdf,全国计算机等级考试二级MSoffice讲义看看[整理].pdf...
  14. 零电压开关(ZVS)电路原理与设计(整理)
  15. 校园英语杂志校园英语杂志社校园英语编辑部2022年第15期目录
  16. amcharts php,amcharts实现动态数据介绍
  17. Sonarqube 扫描maven项目
  18. ubuntu下使用testerSunshine12306抢票程序
  19. 网络工程师学习必备!路由器的工作原理,你真的懂了吗?【超详细|深度解析】
  20. #2微信小程序错误:音乐API调用音乐URL时出现错误

热门文章

  1. 【ElasticSearch】Es 源码之 NodeService 源码解读
  2. 【SpringCloud】服务网关 gateway 和 zuul
  3. 90-50-010-源码-hbase的rowkey设计
  4. IntelliJ IDEA 配置Tomcat 运行Web项目
  5. 15-Scala使用Option、Some、None,避免使用null
  6. 03-centos 如何查看操作系统是哪个版本
  7. 《spring-boot学习》-04-综合开发
  8. GitLab 配置 OAuth2 实现第三方登录,简直太方便了!
  9. 当我们谈微服务,我们在谈什么?谈谈我对微服务的理解!
  10. IntelliJ IDEA 开启很慢,运行不流畅,大项目卡顿?一招配置解决!