一,socket进阶
在前面的博客中讲到了一些基本的计算机网络知识,有一点也是为我在要考传输与交换看到一个题,然后就看到说ARP属于网络层,因为ARP协议跟网络相关,但是我前面的博客说的是ARP协议属于数据链路层。当时我就呆了,不会讲错了吧,后来查了一下,原来都是可以的,ARP协议有的人说在网络层也行,在数据链路层也行。当然这只是一个小插曲。昨天在讲到socket的几种情况还没解决,这篇文章就跟大家解决。大概有几个问题,一个是每次只能接受一定数据大小的数据,如果数据太大怎么办?还有提到的粘包的问题,还有一个就是只能同时一个客户端连上服务器,其他服务器都要等着。
1,先用socket实现一个简单的ssh
ssh服务端
1 import socket,os
2 server=socket.socket()
3 server.bind(('127.0.0.1',1314))
4 server.listen()
5 while True:
6 conn,addr=server.accept()
7 try:
8 while True:
9 data=conn.recv(1024)
10 print('客户端发来的命令是:',data.decode())
11 if not data:break
12 if len(data)==0:
13 print('命令为空')
14 send_data=os.popen(data.decode()).read()#执行命令,并读出结果
15 conn.send(send_data.encode())
16 except ConnectionResetError as e:
17 print('一个客户端断开连接')
18 conn.close()
19 server.colse()
ssh客户端
1 import socket
2 client=socket.socket()
3 client.connect(('127.0.0.1',1314))
4 while True:
5 data=input('>>>')
6 if len(data)==0:continue
7 client.send(data.encode())
8 recv_data=client.recv(1024)
9 print(recv_data.decode())
10 client.close()
写好了,忍不住要开始装逼了,于是你在客户端输入了一个dir运行结果如下
>>>dir
驱动器 E 中的卷是 新加卷
卷的序列号是 CA7D-FFB5
E:\zzq_python\博客 的目录
2018/06/29 15:49 <DIR> .
2018/06/29 15:49 <DIR> ..
2018/06/24 22:36 1,709 calculator.py
2018/06/26 09:34 1,048 deal_error.py
2018/06/28 18:08 349 socket_client.py
2018/06/28 18:06 453 socket_server.py
2018/06/29 15:47 253 ssh_client.py
2018/06/29 15:49 613 ssh_server.py
2018/06/26 16:50 1,508 单例模式.py
2018/06/26 10:22 454 接口类.py
8 个文件 6,387 字节
2 个目录 60,092,284,928 可用字节
但是想了想不得行,这个还不够啊,于是你查了一些你电脑的ip地址,运行结果就不贴出来了。你会惊奇的发现,怎么回事啊。为什么没有显示完呢。仔细想了想,出现前面提到的问题了,每次接收只能接收固定长度的数据,但是超出了只有在下一次接收的时候接收了,那肯定是不行的啊,这种情况,那也太low了吧。于是为了解决这种问题,我们可以先发一个文件的长度,然后客户端接收到以后,根据接收的文件长度跟实际长度比较,知道收完为止。emmm,带着这种想法,我们就来试试实现吧。
2,升级版ssh
ssh服务端
1 import socket,os
2 server=socket.socket()
3 server.bind(('127.0.0.1',1314))
4 server.listen()
5 while True:
6 conn,addr=server.accept()
7 try:
8 while True:
9 data=conn.recv(1024)
10 print('客户端发来的命令是:',data.decode())
11 if not data:break
12 if len(data)==0:
13 print('命令为空')
14 send_data=os.popen(data.decode()).read()#执行命令,并读出结果
15 data_len=len(send_data.encode())
16 print('发送的数据总长度:',data_len)
17 conn.send(str(data_len).encode())
18 print(conn.recv(1024).decode())
19 conn.send(send_data.encode())
20 except ConnectionResetError as e:
21 print('一个客户端断开连接')
22 conn.close()
23 server.colse()
ssh客户端
1 import socket
2 client=socket.socket()
3 client.connect(('127.0.0.1',1314))
4 while True:
5 data=input('>>>')
6 if len(data)==0:continue
7 client.send(data.encode())
8 data_len=client.recv(1024).decode()
9 client.send('接收到数据长度了'.encode())
10 get_len=0#设置最开始长度为0
11 get_data=b''
12 while get_len<int(data_len):
13 data=client.recv(1024)#接收的数据
14 get_len+=len(data)#接收的长度
15 get_data+=data
16 print('数据长度为:',data_len,get_data.decode())
17 client.close()
当然有的人会对这个代码感到疑惑,其中为什么在跟客户端发送完数据长度以后,不直接发送数据内容,中间要接收客户端发来的接收数据长度成功,很多人会觉得这是累赘,但是如果你连续两次发送,这种情况就有可能会出现粘包现象,为了解决这个问题,所以在中途增加了一个接收客户端的信息。讲到这里就解决了两个问题了,一个数据过长,一个粘包的问题,还有一个问题就是不能存在多客户端同时跟服务端交互的问题。
3,实现文件传输
在前面的一个ssh做基础的情况下,我们是不是也能跟ftp一样传文件这些呢,当然可以肯定的告诉你,可以传文件的,而且在后面的学习完成以后,你还能自己写一个ftp实现上传下载文件的功能。先做一个简单的文件传输功能吧。
服务端(server)
1 import socket,os
2 server=socket.socket()
3 server.bind(('127.0.0.1',1314))
4 server.listen()
5 while True:
6 conn,addr=server.accept()
7 print('连接成功!')
8 try:
9 while True:
10 file_name=conn.recv(1024).decode()
11 if not file_name: break
12 if os.path.isfile(file_name):#判断文件是否存在
13 file_len=os.stat(file_name).st_size#获取文件大小
14 conn.send(str(file_len).encode())
15 conn.recv(1024)
16 with open(file_name,'rb') as f:
17 for i in f:
18 conn.send(i)
19 print('文件发送完成')
20 else:
21 print('文件不存在')
22 except ConnectionResetError:
23 print('一个客户端断开')
24 finally:
25 conn.close()
26 server.close()
客户端(client)
1 import socket
2 client=socket.socket()
3 client.connect(('127.0.0.1',1314))
4 while True:
5 file_name=input(">>>")
6 if len(file_name)==0:continue
7 client.send(file_name.encode())
8 file_len=client.recv(1024).decode()
9 client.send('接收数据长度成功'.encode())
10 get_len=0
11 f=open(file_name,'wb')
12 while get_len<float(file_len):
13 data=client.recv(1024)
14 get_len+=len(data)
15 f.write(data)
16 print('已经完成',get_len,'/',file_len)
17 print('文件传输完成')
18 f.close()
19 client.close()
基本socket的用法就讲完了,当然在使用文件传输的时候,最好是用前面学习的hashlib模块进行文件内容的加密,这里就不写了,感兴趣可以试着写一写,在学习文件传输以后,就可以写一个简单的ftp了。能够实现文件的上传和下载了,上传就是跟下载相反。不过还是不能实现多个客户端同时与服务端交互。下面的这个socketserver就很好的解决了这个问题。
二,socketserver用法
前面都是为最后面的装逼做铺垫的,没错的,下面即将进入的是我们今天的装逼操作了,socketserver。
当然这里我们也只是写简单的用法,其实用法跟socket用法是差不多的,所以只给了简单的使用方法
服务端(server)
1 import socketserver
2 class MyServer(socketserver.BaseRequestHandler):
3 def handle(self):#里面是跟客户端交互的全过程
4 while True:
5 try:
6 data=self.request.recv(1024) #self.request相当于socket里面的conn
7 print('收到来自客户端%s的消息:%s' %(self.request,data.decode()))
8 self.request.send(data.upper())
9 except ConnectionResetError as e:
10 print('error:',e)
11 break
12 if __name__ == '__main__':
13 #创建一个服务,绑定ip跟端口
14 server=socketserver.ThreadingTCPServer(('127.0.0.1',1314),MyServer)
15 server.serve_forever()#服务一直开启
客户端(client)
1 import socket
2 client=socket.socket()
3 client.connect(('127.0.0.1',1314))
4 while True:
5 data=input('>>>')
6 client.send(data.encode())
7 get_data=client.recv(124)
8 print(get_data.decode())
9 client.close()
这里客户端还是使用的socket的方法,多连接只是相当于服务端来说的。
基本已经学完了网络编程,也能自己实现一个完整的ftp了,虽然有点困难,但是还是推荐自己实现一个,可以加强对代码的熟悉,而且还能练习到前面学习的东西。马上期末了,好多作业要做,还要为期末考试做准备,还要准备毕业设计,还要准备找实习工作。哎,感觉有点难受,最近烦心事也是挺多的。写博客,最开始为了回顾以前学过的知识,把以前自己做的学习笔记从word搬到博客上,现在慢慢也成了自己有时候类似写日记的地方了。挺迷茫的,一个啥子都不会的大学生,周围优秀的人越来越优秀,不过还好有你陪我,你教会了我挺多的,希望我付出的努力以后能给你带来幸福。
来源:oschina
链接:https://my.oschina.net/u/4387108/blog/3921666