《零基础学Python》Python的网络编程【十九】

整体文章目录

整体目录

一、 当前章节目录

在这里插入图片描述

二、网络模型介绍

2.1 OSI简介

1983年,国际标准化组织(ISO)发布了著名的ISO/IEC7498标准,也就是开放式系统互连参考模型(OSI)。这个标准定义了网络的七层框架,试图使计算机在整个世界范围内实现互联。HTTP属于应用层的协议。

  1. 物理层:定义了通信设备的传输规范,规定了激活、维持和关闭通信节点之间的机械特性、电气特性和功能特性等。
  2. 数据链路层:定义数据封装以及传送的方式。
  3. 网络层:定义了数据的寻址和理由方式。
  4. 传输层:为数据提供端到端传输。
  5. 会话层:用来为通信的双方制定通信方式,包括建立和拆除会话。
  6. 表示层:为不同的用户提供数据和信息的转换。
  7. 应用层:控制着用户绝大多数对于网络应用程序的访问,提供了访问网络服务的接口。

在这里插入图片描述

2.2 TCP/IP简介

TCP/IP为互联网的最早的通信协议,TCP为传输层的协议,而IP则为网络层的协议。TCP/IP协议出现的比OSI早,所以并不符合OSI模型。
在这里插入图片描述

三、Socket应用

3.1 Socket基础

  • Socket(套接字)编程也已经成为网络中传送和接收数据的首选方法。
  • 套接字相当于应用程序访问下层网络服务的接口。
  • 使用套接字,可以使得不同的主机之间进行通信,从而实现数据交换。

在这里插入图片描述

3.2 Socket的工作方式

套接字在工作的时候将连接的对端分成服务器和客户端,这也是CS(客户端-服务器端)模式的由来。
在这里插入图片描述在这里插入图片描述

四、服务器端和客户端通信

4.1 服务器端的构建

  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
  1. 通用的时间服务程序
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函数生成服务进程
  1. 使用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方式

  1. 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)     # 打印接收到的数据
  1. 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()       # 进入循环

七、习题

习题:

  1. TCP/IP从低到高分为几个层次?分别是哪些?
  2. Socket是什么?它与TCP/IP有什么联系?
  3. 使用Python的SocketServer模块编写一个简单的聊天程序,包括客户端与服务器端。

答案:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值