python --- 网络编程Socket
网络编程
定义:所为网络编程即是对信息的发送和接收。
主要工作:
(1)发送端:将信息以规定的协议组装成数据包。
(2)接收端:对收到的数据包解析,以提取所需要的信息。
Socket:两个在网络上的程序通过一个双向的通信连接,实现数据的交换,此连接的一端称为一个socket。
Socket的本质:Socket是一个编程接口(API),TCP/IP协议需要向开发者提供做网络开发用的接口,这就是Socket接口,它是对TCP/IP协议网络通信的封装。
python中用有标准库socket,要进行socket编程,只需导入这个模块即可。
例一(实现一个单对单,只能发送一次消息的一次性服务端和客户端):
#服务端
import socket address = ("localhost", 6666) #写明服务端要监听的地址,和端口号
server = socket.socket() #生成一个socket对象
server.bind(address) #用socket对象绑定要监听的地址和端口
server.listen() #开始监听 conn,addr = server.accept() #等带新连接接入服务端,返回一个新的socket对象和地址,地址格式同前面格式
'''
Wait for an incoming connection. Return a new socket
representing the connection, and the address of the client.
'''
data = conn.recv(1024) #接收信息,写明要接收信息的最大容量,单位为字节
print("server recv:", data)
conn.send(data.upper()) #对收到的信息处理,返回到客户端 server.close() #关闭服务端
socket_server
#客户端
import socket address = ('localhost', 6666) #写明要发送消息的服务端的地址和端口号
client = socket.socket()
client.connect(address) #连接服务端 client.send(b"hell world") #发送信息,注意在python3中socket的发送只支持bytes类型
data = client.recv(1024) #等待接收服务端返回的信息
print("client recv:", data) client.close() #关闭客户端
socket_client
例二(对上面的代码进行改进,可以挂起多个连接,使每个连接可以进行多次对话且上一个连接断开后下一个连接马上接入):
#服务端
import socket address = ("localhost", 6666) #写明服务端要监听的地址,和端口号
server = socket.socket() #生成一个socket对象
server.bind(address) #用socket对象绑定要监听的地址和端口
server.listen(5) #开始监听 while True:
#一条连接关闭后,接入下一条连接
conn,addr = server.accept() #等带新连接接入服务端,返回一个新的socket对象和地址,地址格式同前面格式
'''
Wait for an incoming connection. Return a new socket
representing the connection, and the address of the client.
'''
while True:
#使其可以接收多次消息
data = conn.recv(1024) #接收信息,写明要接收信息的最大容量,单位为字节
# 没收到消息,断开本次连接
if not data:
break
print("server recv:", data)
conn.send(data.upper()) #对收到的信息处理,返回到客户端 server.close() #关闭服务端
socket_server2
#客户端
import socket address = ('localhost', 6666) #写明要发送消息的服务端的地址和端口号
client = socket.socket()
client.connect(address) #连接服务端 while True:
#使其可以向服务端多次发送消息
msg = input(">>>:").strip()
#如果发送的消息为空,则不再发送
if len(msg) == 0:
break
msg = msg.encode('utf-8') #将要发送的消息转为bytes类型
client.send(msg) #发送信息,注意在python3中socket的发送只支持bytes类型
data = client.recv(1024) #等待接收服务端返回的信息
print("client recv:", data.decode()) client.close() #关闭客户端
socket_client2
例三(对例二稍加改造,就可实现一个简单的ssh的服务端和客户端):
#服务端
import socket
import os address = ("localhost", 8888) #写明服务端要监听的地址,和端口号
server = socket.socket() #生成一个socket对象
server.bind(address) #用socket对象绑定要监听的地址和端口
server.listen() #开始监听 while True:
#一条连接关闭后,接入下一条连接
conn,addr = server.accept() #等带新连接接入服务端,返回一个新的socket对象和地址,地址格式同前面格式
'''
Wait for an incoming connection. Return a new socket
representing the connection, and the address of the client.
'''
while True:
data = conn.recv(1024) #接收信息,写明要接收信息的最大容量,单位为字节
# 没收到消息,断开本次连接
if not data:
break
cmd_result = os.popen(data.decode(), 'r').read() #执行命令,将命令执行结果保存到cmd_result
if len(cmd_result) == 0:
'''命令执行结果为空,认为接收到错误命令'''
cmd_result = "It's a wrong command..." while True:
conn.send(str(len(cmd_result)).encode('utf-8')) #发送命令执行结果的长度
confirm = conn.recv(1024).decode()
'''客户端确认收到数据长度,发送数据,否则重传;且解决粘包问题'''
if confirm == "OK":
conn.send(cmd_result.encode('utf-8')) #对收到的信息处理,返回到客户端
break
else :
continue server.close() #关闭服务端
ssh_socket_server
import socket address = ("localhost", 8888)
client = socket.socket()
client.connect(address) while True:
cmd = input("(command)>>>:").strip()
if len(cmd) == 0:
'''发送空命令时,结束本次循环'''
continue
if cmd == "#exit":
'''当检测到#exit,客户端与服务端断开连接'''
break client.send(cmd.encode()) #向服务端发送命令 cmd_result = '' #目前已接收的数据
size_data = 0 #目前已接收数据的长度
size_cmd_result = int(client.recv(1024).decode()) #接收命令执行结果的长度
client.send("OK".encode("utf-8")) #向服务端确认收到数据长度
while size_data < size_cmd_result:
'''命令的执行结果可能大于设置的接收buffersize,多次接收'''
data = client.recv(1024).decode() #每次接收的数据
size_data += len(data)
cmd_result += data print(cmd_result) client.close()
ssh_socket_client
注:提供另一种接收思路,服务端可以在每次返送完命令执行结果后,再发送一个结束标志,当客户端检测到结束标志时停止循环接收。
例四(改造例三,就可以实现一个简单的ftp的服务端和客户端)
#/usr/bin/python3
#服务端
import socket
import os
import hashlib address = ("0.0.0.0", 8888) #写明服务端要监听的地址,和端口号
server = socket.socket() #生成一个socket对象
server.bind(address) #用socket对象绑定要监听的地址和端口
server.listen() #开始监听 while True:
#一条连接关闭后,接入下一条连接
conn,addr = server.accept() #等带新连接接入服务端,返回一个新的socket对象和地址,地址格式同前面格式
'''
Wait for an incoming connection. Return a new socket
representing the connection, and the address of the client.
'''
while True:
content = os.popen('ls', 'r').read()
conn.send(content.encode('utf-8')) #与客户端建立连接后,将服务端有哪些文件发给客户端,供客户端选择
filename = conn.recv(1024).decode() #接收客户端发来的文件名 if os.path.isfile(filename):
'''文件存在,开始发送文件'''
file_md5 = hashlib.md5() #初始化MD5对象,用于传输完成后的校验
file_size = os.stat(filename)[6] #读取文件大小
conn.send(str(file_size).encode('utf-8')) #将文件size发给客户端
confirm = conn.recv(1024).decode() #等待客户端确认接收
if confirm == "OK":
'''发送文件数据'''
with open(filename, 'rb') as fp:
for line in fp:
file_md5.update(line)
conn.send(line) client_md5 = conn.recv(1024).decode() #传输完成后接收客户端发来的MD5
if file_md5.hexdigest() == client_md5:
'''确认文件传输未出错'''
conn.send("Success...".encode('utf-8'))
else :
'''文件传输出错,提示客户端删除重传'''
conn.send("This file is changed, please delete it and try again...".encode('utf-8')) #客户端未确认接收,重试
else :
conn.send("Error, try again...".encode('utf-8'))
continue else :
'''文件不存在,让客户端重新发送文件名'''
conn.send("The file name is wrong and try again".encode('utf-8')) server.close() #关闭服务端
ftp_socket_server
#/usr/bin/python3
import socket
import hashlib address = ("192.168.56.50", 8888)
client = socket.socket()
client.connect(address) while True:
content = client.recv(4096) #接收并打印服务端有哪些文件
print("Files List".center(75, '-'))
print(content.decode()) #向服务端发送想要接收的文件名
filename = input("(You want to get)>>>:").strip()
if filename == '#exit':
break
client.send(filename.encode('utf-8')) file_size = client.recv(1024).decode()
if file_size.isdigit():
'''文件大小是不小于0的数字,则文件存在,准备接收'''
file_size = int(file_size)
if file_size >= 0:
data_size = 0
data_md5 = hashlib.md5() #初始化MD5对象,用以向服务端校验
client.send("OK".encode('utf-8')) #向服务端确认接收数据
with open(filename, 'wb') as fp:
while data_size < file_size:
data = client.recv(1024)
data_md5.update(data)
data_size += len(data)
fp.write(data)
client.send(data_md5.hexdigest().encode('utf-8')) #发送服务端发送数据的MD5码
message = client.recv(1024).decode() #接收并打印服务端的校验信息
print(message)
print('\n\n\n')
else :
'''文件大小不是数字,则出错,打印服务端的提示信息'''
print(file_size)
continue client.close()
ftp_socket_client
注意:如果代码中有两个(或两个以上)socket.send()连在一起(中间无阻塞(比如time.slee(), socket.recv()等)),有粘包风险。
通过上面的代码编写,可以发现尽管socket已经简化了网络编程的过程,但还是给人一种面向过程的感觉。记下来的socketserver便解决了网络服务端编程过于繁琐的问题。
socketserver:
socketserver
模块简化了编写网络服务器的任务。
有四个基本的具体服务器类:
- class
socketserver.
TCPServer
(server_address, RequestHandlerClass, bind_and_activate=True) -
这使用Internet TCP协议,它在客户端和服务器之间提供连续的数据流。如果bind_and_activate为true,构造函数将自动尝试调用
server_bind()
和server_activate()
。其他参数传递到BaseServer
基类。
- class
socketserver.
UDPServer
(server_address, RequestHandlerClass, bind_and_activate=True) -
这使用数据报,其是可能在运输中不按顺序到达或丢失的信息的离散分组。参数与
TCPServer
相同。
- class
socketserver.
UnixStreamServer
(server_address, RequestHandlerClass, bind_and_activate=True) - class
socketserver.
UnixDatagramServer
(server_address, RequestHandlerClass, bind_and_activate=True) -
这些更常用的类与TCP和UDP类类似,但使用Unix域套接字;它们在非Unix平台上不可用。参数与
TCPServer
相同。
这四个类同时处理请求;每个请求必须在下一个请求开始之前完成。如果每个请求需要很长时间来完成,这是不合适的,因为它需要大量的计算,或者因为它返回了很多客户端处理速度慢的数据。解决方案是创建一个单独的进程或线程来处理每个请求; ForkingMixIn
和ThreadingMixIn
混合类可以用于支持异步行为。
创建服务器需要几个步骤。首先,您必须通过对BaseRequestHandler
类进行子类化并覆盖其handle()
方法来创建请求处理程序类;此方法将处理传入请求。其次,您必须实例化一个服务器类,将它传递给服务器的地址和请求处理程序类。然后调用服务器对象的handle_request()
或serve_forever()
方法来处理一个或多个请求。最后,调用server_close()
关闭套接字。
当从ThreadingMixIn
继承线程连接行为时,应该明确声明您希望线程在突然关闭时的行为。ThreadingMixIn
类定义了一个属性daemon_threads,它指示服务器是否应该等待线程终止。如果您希望线程自主行为,您应该明确地设置标志;默认值为False
,这意味着Python不会退出,直到ThreadingMixIn
创建的所有线程都退出。
#四个基本类的继承关系
+------------+
| BaseServer |
+------------+
|
v
+-----------+ +------------------+
| TCPServer |------->| UnixStreamServer |
+-----------+ +------------------+
|
v
+-----------+ +--------------------+
| UDPServer |------->| UnixDatagramServer |
+-----------+ +--------------------+
例五(我们使用socketserver实现例二):
import socketserver class MyTCPRequestHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server. It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
"""
服务端和客户端连接后,数据的交互由这个方法实现,这个方法必须重写
"""
while True:
try:
self.data = self.request.recv(1024).strip()
print("server recv:", self.data.decode())
self.request.send(self.data.upper())
except ConnectionResetError:
break if __name__ == "__main__":
HOST, PORT = "localhost", 6666
server = socketserver.TCPServer((HOST, PORT), MyTCPRequestHandler)
server.serve_forever() #处理请求
server.server_close() #关闭套接字
TCPSever
注:服务器类具有相同的外部方法和属性,无论它们使用什么网络协议。
例六(使用ThreadingMixIn可以轻松实现一对多同时服务(多线程)
):
import socketserver class MyTCPRequestHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server. It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
"""
def handle(self):
"""
服务端和客户端连接后,数据的交互由这个方法实现,这个方法必须重写
"""
while True:
try:
self.data = self.request.recv(1024).strip()
print("server recv:", self.data.decode())
self.request.send(self.data.upper())
except ConnectionResetError:
break if __name__ == "__main__":
HOST, PORT = "localhost", 6666
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPRequestHandler) #同时处理多个连接
server.serve_forever() #处理请求
server.server_close() #关闭套接字 #ThreadingTCPServer的源码
'''
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
'''
ThreadingTCPServer
注:其他协议的多线程实现同上。
PS(本例中所涉及到的模块使用参考):
socket模块:http://www.cnblogs.com/God-Li/p/7625825.html
hashlib模块:http://www.cnblogs.com/God-Li/p/7631604.html
os模块:http://www.cnblogs.com/God-Li/p/7384227.html
socketserver模块:http://python.usyiyi.cn/translate/python_352/library/socketserver.html#module-socketserver
python --- 网络编程Socket的更多相关文章
- Day07 - Python 网络编程 Socket
1. Python 网络编程 Python 提供了两个级别访问网络服务: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口 ...
- Python网络编程socket
网络编程之socket 看到本篇文章的题目是不是很疑惑,what is this?,不要着急,但是记住一说网络编程,你就想socket,socket是实现网络编程的工具,那么什么是socket,什么是 ...
- python网络编程-socket编程
一.服务端和客户端 BS架构 (腾讯通软件:server+client) CS架构 (web网站) C/S架构与socket的关系: 我们学习socket就是为了完成C/S架构的开发 二.OSI七层 ...
- python网络编程socket /socketserver
提起网络编程,不同于web编程,它主要是C/S架构,也就是服务器.客户端结构的.对于初学者而言,最需要理解的不是网络的概念,而是python对于网络编程都提供了些什么模块和功能.不同于计算机发展的初级 ...
- Python网络编程-Socket简单通信(及python实现远程文件发送)
学习python中使用python进行网络编程,编写简单的客户端和服务器端进行通信,大部分内容来源于网络教程,这里进行总结供以后查阅. 先介绍下TCP的三次握手: 1,简单的发送消息: 服务器端: i ...
- Day10 Python网络编程 Socket编程
一.客户端/服务器架构 1.C/S架构,包括: 1.硬件C/S架构(打印机) 2.软件C/S架构(web服务)[QQ,SSH,MySQL,FTP] 2.C/S架构与socket的关系: 我们学习soc ...
- python网络编程——socket基础篇
python的网络编程比c语言简单许多, 封装许多底层的实现细节, 方便程序员使用的同时, 也使程序员比较难了解一些底层的东西. 1 TCP/IP 要想理解socket,首先得熟悉一下TCP/IP协议 ...
- Python 网络编程——socket
一 客户端/服务器架构 客户端(Client)服务器(Server)架构,即C/S架构,包括 1.硬件C/S架构(打印机) 2.软件C/S架构(web服务) 理想/目标状态—— 最常用的软件服务器是 ...
- Python网络编程—socket(二)
http://www.cnblogs.com/phennry/p/5645369.html 接着上篇博客我们继续介绍socket网络编程,今天主要介绍的内容:IO多路复用.多线程.补充知识点. 一.I ...
随机推荐
- Google的SPDY协议成为HTTP 2.0的基础
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt384 据TNW援引 IFTF HTTP 工作组主席 Mark Notting ...
- C# 反向生成工具(DAL BLL Modle)
VS2015 ADO.NET无果后果断~! 动软生成:http://pan.baidu.com/s/1gfIf0ZL
- ASP.NET 控制器
1.继承Controller public class TestController : Controller2.编写控制器方法 // URL : test/Edit/1 [ ...
- 在数组a中,a[i]+a[j]=a[k],求a[k]的最大值,a[k]max——猎八哥fly
在数组a中,a[i]+a[j]=a[k],求a[k]的最大值,a[k]max. 思路:将a中的数组两两相加,组成一个新的数组.并将新的数组和a数组进行sort排序.然后将a数组从大到小与新数组比较,如 ...
- 软工+C(2017第2期) 分数和checklist
// 上一篇:题目设计.点评和评分 // 下一篇:超链接 教学里,建立清晰明确的评分规则并且一开始就公布,对于教师.助教.学生都是重要的. 公布时机 在课程开始的时候,就需要确定并公布评分机制,随着课 ...
- 2D命令行小游戏Beta1.0
前提: 遇到许多问题,没有参考大佬一些方法是敲不出来的...Orz using System; using System.Collections.Generic; using System.Linq; ...
- Swing-JList选择事件监听器ListSelectionListener-入门
当JList中的元素被选中时,选择事件将被触发.对于JTable也是一样,你可以把它看做是多个并列的JList.那么,如果程序需要对该事件做出响应,需要以下步骤: (1)创建一个实现了 ListSel ...
- 学号:201521123116 《java程序设计》第八周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结集合与泛型相关内容. 1.2 选做:收集你认为有用的代码片段 List<Entry<String,Integer> ...
- 学号:201521123116 《java程序设计》第七周学习总结
1. 本周学习总结 2. 书面作业 Q1 ArrayList代码分析 1.1 解释ArrayList的contains源代码ArrayList的contains源代码 1.2 解释E remove(i ...
- 201521123045 《Java程序设计》第12周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 2. 书面作业 将Student对象(属性:int id, String name,int age,doubl ...