整体文章目录
一、 当前章节目录
二、网络模型介绍
2.1 OSI简介
1983年,国际标准化组织(ISO)发布了著名的ISO/IEC7498标准,也就是开放式系统互连参考模型(OSI)。这个标准定义了网络的七层框架,试图使计算机在整个世界范围内实现互联。HTTP属于应用层的协议。
- 物理层:定义了通信设备的传输规范,规定了激活、维持和关闭通信节点之间的机械特性、电气特性和功能特性等。
- 数据链路层:定义数据封装以及传送的方式。
- 网络层:定义了数据的寻址和理由方式。
- 传输层:为数据提供端到端传输。
- 会话层:用来为通信的双方制定通信方式,包括建立和拆除会话。
- 表示层:为不同的用户提供数据和信息的转换。
- 应用层:控制着用户绝大多数对于网络应用程序的访问,提供了访问网络服务的接口。
2.2 TCP/IP简介
TCP/IP为互联网的最早的通信协议,TCP为传输层的协议,而IP则为网络层的协议。TCP/IP协议出现的比OSI早,所以并不符合OSI模型。
三、Socket应用
3.1 Socket基础
- Socket(套接字)编程也已经成为网络中传送和接收数据的首选方法。
- 套接字相当于应用程序访问下层网络服务的接口。
- 使用套接字,可以使得不同的主机之间进行通信,从而实现数据交换。
3.2 Socket的工作方式
套接字在工作的时候将连接的对端分成服务器和客户端,这也是CS(客户端-服务器端)模式的由来。
四、服务器端和客户端通信
4.1 服务器端的构建
- 一个简单的服务程序
# one.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 生成socket对象
host = "127.0.0.1"
port = 1234
s.bind((host, port)) # 绑定socket地址
s.listen(10) # 开始监听
print("等待客户端连接……")
while True:
c, addr = s.accept() # 接受一个连接
print('Get connection from', addr)
data = "This is a simple server"
c.send(data) # 发送数据
c.close() # 关闭连接
# 服务器端的输出
In [1]: %run one.py
# 客户端的输出(另外一个终端)
In [1]: !telnet 127.0.0.1 1234
This is a simple server
- 通用的时间服务程序
import socket
import datetime
import sys
DEFAULT_PORT = 1234 # 默认端口
def timeServer(port):
host = "127.0.0.1" # 使用本机地址
s = None
for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): # 在本机的所有地址监听
af, socktype, proto, canonname, sockaddr = res
try:
s = socket.socket(af, socktype, proto)
except socket.error as msg:
s = None
continue
try:
s.bind(sockaddr) # 绑定socket地址
s.listen(10) # 开始监听
print("等待客户端连接……")
except socket.error as msg:
s.close()
s = None
continue
break
if s is None: # 生成socket出错
print('could not open socket')
return 1
while True:
c, addr = s.accept()
print('Get connection from', addr)
data = str(datetime.datetime.now()).encode()
c.send(data) # 发送当前时间
print(str(datetime.datetime.now()))
c.close()
if __name__ == '__main__':
port = DEFAULT_PORT
if len(sys.argv) > 1: #判断用户的输入
try:
port = int(sys.argv[1])
if port < 0 or port >= 65536: # 端口的范围判断
port = DEFAULT_PORT
except (Exception, e):
port = DEFAULT_PORT
timeServer(port) # 调用timeServer函数生成服务进程
- 使用SocketServer模块
from socketserver import TCPServer, StreamRequestHandler
class MyHandler(StreamRequestHandler):
def handle(self): # 重载处理方法
addr = self.request.getpeername() # 获取连接对端地址
print('Get connection from', addr)
self.wfile.write('This is a tcp socket server'.encode()) # 发送数据
host = '127.0.0.1'
port = 1234
server = TCPServer((host, port), MyHandler) # 生成TCP服务器
server.serve_forever() # 开始监听并处理连接
4.2 客户端的构建
import socket
s = socket.socket() # 生成一个socket对象
server = "127.0.0.1"
port = 1234
s.connect((server, port)) # 连接服务器
print(s.recv(1024)) # 读取数据
s.close() # 关闭连接
五、异步通信方式
- 在上面的示例中,所有的服务器端的实现都是同步的。也就是说,服务程序只有处理完一个连接后,才能处理另外一个连接。
- 如果需要让服务器端应用程序能够同时处理多个连接,则需要使用异步通信方式。
5.1 使用Fork方式
# 只适用于Linux系统,由于在Windows下没有ForkingMixIn类,将会报错。
from socketserver import TCPServer, ForkingMixIn, StreamRequestHandler
import time
class Server(ForkingMixIn, TCPServer): # 自定义Server类
pass
class MyHandler(StreamRequestHandler):
def handle(self): # 重载handle函数
addr = self.request.getpeername()
print('Get connection from', addr) # 打印客户端地址
time.sleep(5) # 休眠5秒钟
self.wfile.write('This is a ForkingMixIn tcp socket server'.encode()) # 发送信息
host = '127.0.0.1'
port = 1234
server = Server((host, port), MyHandler)
server.serve_forever() # 开始侦听并处理连接
5.2 使用线程方式
from socketserver import TCPServer, ThreadingMixIn, StreamRequestHandler
import time
class Server(ThreadingMixIn, TCPServer): # 自定义Server类
pass
class MyHandler(StreamRequestHandler):
def handle(self): # 重载handle函数
addr = self.request.getpeername()
print('Get connection from', addr) # 打印客户端地址
time.sleep(5) # 休眠5秒钟
self.wfile.write('This is a ThreadingMixIn tcp socket server'.encode())
host = '127.0.0.1'
port = 1234
server = Server((host, port), MyHandler)
server.serve_forever() # 开始监听并处理连接
5.3 使用异步IO方式
- select 方法
import socket, select
s = socket.socket() # 生成socket对象
host = socket.gethostname()
port = 1234
s.bind((host, port)) # 绑定套接口地址
s.listen(5) # 开始服务器端监听
inputs = [s]
while True:
rs, ws, es = select.select(inputs, [], []) # 使用select方法
for r in rs:
if r is s:
c, addr = s.accept() # 处理连接
print('Get connection from', addr)
inputs.append(c)
else:
try:
data = r.recv(1024) # 接收数据
disconnected = not data
except socket.error:
disconnected = True
if disconnected:
print(r.getpeername(), 'disconnected')
inputs.remove(r)
else:
print(data) # 打印接收到的数据
- poll方法
import socket
import select # 生成socket对象
s = socket.socket()
host = socket.gethostname()
port = 1234
s.bind((host, port)) # 绑定套接口地址
fd_dict = {s.fileno(): s}
s.listen(5) # 开始服务器端监听
p = select.poll() # 生成Polling对象
p.register(s) # 注册socket对象
while True:
events = p.poll() # 获取准备好的文件对象
for fd, event in events:
if fd in fd_dict:
c, addr = s.accept() # 处理连接
print('Got connection from', addr)
p.register(c)
fd_dict[c.fileno()] = c # 加入连接socket
elif event & select.POLLIN:
data = fd_dict[fd].recv(1024) # 接收事件
if not data:
print(fd_dict[fd].getpeername(), 'disconnected')
p.unregister(fd) # 取消注册
del fd_dict[fd]
else:
print(data) # 打印数据
5.4 使用asyncore模块
dddws
import asyncore, socket
class HttpClient(asyncore.dispatcher): # 定义了一个HttpClient类
def __init__(self, host, path): # 类的构造函数
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM) # 创建socket对象
self.connect((host, 80))
self.buffer = ('Get %s HTTP/1.0\r\n\r\n' % path).encode()
def handle_connect(self): # 连接调用接口
pass
def handle_close(self): # 接口关闭函数
self.close()
def handle_read(self): # 读取数据
print(self.recv(1024))
def handle_write(self): # 写入数据
sent = self.send(self.buffer)
self.buffer = self.buffer[sent:]
def writable(self): # 判断是否写入数据
return (len(self.buffer) > 0)
if __name__ == '__main__':
c = HttpClient('www.python.org', '/')
asyncore.loop() # 开始异步通信处理方式
六、Twisted网络框架
6.1 Twisted框架介绍
- Twisted是一个面向对象、基于事件驱动的顶级通信框架,可以完成大部分的网络应用任务。
- Twisted框架具有很好的网络性能,提供了异步通信机制。
- 采用事件驱动方式,只需要在事件发生的点构建相应的代码就可以了。
- 模块化的组件组成:协议、工厂、反应器和Deferred对象。
6.2 Twisted框架下服务器端的实现
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
class SimpleServer(Protocol):
def connectionMade(self): # 连接建立的时候
print('Get connection from', self.transport.client)
def connectionLost(self, reason): #连接断开的时候
print(self.transport.client, 'disconnected')
def dataReceived(self, data): # 接收数据的时候
print(data)
factory = Factory()
factory.protocol = SimpleServer
port = 1234
reactor.listenTCP(port, factory)
reactor.run() # 进入循环
6.3 Twisted框架下服务器端的其他处理
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
from twisted.protocols.basic import LineReceiver
class SimpleServer(LineReceiver):
def connectionMade(self): # 连接建立的时候
print('Get connection from', self.transport.client)
def connectionLost(self, reason): #连接断开的时候
print(self.transport.client, 'disconnected')
def dataReceived(self, line): # 接收数据的时候
print(line)
factory = Factory()
factory.protocol = SimpleServer
port = 1234
reactor.listenTCP(port, factory)
reactor.run() # 进入循环
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
class SimpleServer(Protocol):
def connectionMade(self): # 连接建立的时候
print('Get connection from', self.transport.client)
self.transport.loseConnection()
factory = Factory()
factory.protocol = SimpleServer
port = 1234
reactor.listenTCP(port, factory)
reactor.run() # 进入循环
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
from twisted.protocols.basic import LineReceiver
class EchoServer(LineReceiver):
def connectionMade(self): # 连接建立的时候
print('Get connection from', self.transport.client)
def lineReceived(self, line): # 接收数据的时候
self.transport.write(line)
factory = Factory()
factory.protocol = EchoServer
port = 1234
reactor.listenTCP(port, factory)
reactor.run() # 进入循环
from twisted.internet import reactor
from twisted.internet.protocol import Protocol, Factory
from twisted.protocols.basic import LineReceiver
class EchoServer():
def __init__(self, factory):
self.factory = factory
def connectionMade(self): # 连接建立的时候
print('Get connection from', self.transport.client)
self.factory.numProtocols = self.factory.numProtocols + 1
if self.factory.numProtocols > 5: # 当连接超过5个的时候,断开连接
self.transport.write("Too many connections, try later".encode())
self.transport.loseConnection()
print('Get connection from', self.transport.client)
def connectionLost(self, reason): #连接断开的时候
self.factory.numProtocols = self.factory.numProtocols - 1
def lineReceived(self, line): # 将收到的数据返回给客户端
self.transport.write(line)
class EchoFactory(Factory):
numProtocols = 0
def __init__(self):
self.myfactory = self
def buildProtocol(self, addr):
return EchoServer(self.myfactory)
endpoint = TCP4ServerEndpoint(reactor, 1234)
endpoint.listen(EchoFactory())
reactor.run() # 进入循环
七、习题
习题:
- TCP/IP从低到高分为几个层次?分别是哪些?
- Socket是什么?它与TCP/IP有什么联系?
- 使用Python的SocketServer模块编写一个简单的聊天程序,包括客户端与服务器端。
答案: