Python(十一)网络与web编程

1.作为客户端与HTTP服务交互

(1)发送一个简单的HTTP GET请求到远程的服务上

from urllib import request, parse

#url的get请求 请求信息连同url一起发送
url = 'http://httpbin.org/get'

#需要请求获取的信息
parms = {
   'name1' : 'value1',
   'name2' : 'value2'
}

# Encode the query string
querystring = parse.urlencode(parms)


u = request.urlopen(url+'?' + querystring)
resp = u.read()

(2)使用POST方法在请求主体中发送查询参数

from urllib import request, parse

# Post请求
url = 'http://httpbin.org/post'

# Dictionary of query parameters (if any)
parms = {
   'name1' : 'value1',
   'name2' : 'value2'
}

# Encode the query string
querystring = parse.urlencode(parms)


u = request.urlopen(url, querystring.encode('ascii'))
resp = u.read()

(3)request第三方库

利用 requests 库发起一个HEAD请求,并从响应中提取出一些HTTP头数据的字段

import requests

resp = requests.head('http://www.python.org/index.html')

status = resp.status_code
last_modified = resp.headers['last-modified']
content_type = resp.headers['content-type']
content_length = resp.headers['content-length']

利用requests库实现post操作

import requests

url = 'http://httpbin.org/post'

parms = {
   'name1' : 'value1',
   'name2' : 'value2'
}

headers = {
    'User-agent' : 'none/ofyourbusiness',
    'Spam' : 'Eggs'
}#头部字段信息

resp = requests.post(url, data=parms, headers=headers) #根据头部设置正文格式 参数以正文形式上传

text = resp.text



files = { 'file': ('data.csv', open('data.csv', 'rb')) } 

r = requests.post(url, files=files) #csv文件为正文进行上传

2.创建TCP服务器

实现一个服务器,通过TCP协议和客户端通信

from socketserver import BaseRequestHandler, TCPServer

class EchoHandler(BaseRequestHandler): #实现了一个 handle() 方法,用来为客户端提供连接服务
    def handle(self):
        print('Got connection from', self.client_address)
        while True: #表示客户端与服务器连接成功 发送客户端请求数据进行回复
            msg = self.request.recv(8192)
            if not msg:
                break
            self.request.send(msg)

if __name__ == '__main__':
    serv = TCPServer(('', 20000), EchoHandler)
    serv.serve_forever()


>>> from socket import socket, AF_INET, SOCK_STREAM
>>> s = socket(AF_INET, SOCK_STREAM) #创建客户端套接字句柄
>>> s.connect(('localhost', 20000))  #连接本地服务器
>>> s.send(b'Hello') #向本地服务器发送二进制数据
5
>>> s.recv(8192) #
b'Hello'
>>>

socketserver 可以让我们很容易的创建简单的TCP服务器。 但是,你需要注意的是,默认情况下这种服务器是单线程的,一次只能为一个客户端连接服务。 如果你想处理多个客户端,可以初始化一个 ForkingTCPServer 或者是 ThreadingTCPServer 对象

from socketserver import ThreadingTCPServer


if __name__ == '__main__':
    serv = ThreadingTCPServer(('', 20000), EchoHandler)
    serv.serve_forever()

使用上述线程服务器有个潜在问题就是它们会为每个客户端连接创建一个新的进程或线程。 由于客户端连接数是没有限制的,因此一个恶意的黑客可以同时发送大量的连接让你的服务器奔溃。

因此 可以创建一个预先分配大小的工作线程池或进程池。 先创建一个普通的非线程服务器,然后在一个线程池中使用 serve_forever() 方法来启动

if __name__ == '__main__':
    from threading import Thread
    NWORKERS = 16  # 线程池最大线程数
    serv = TCPServer(('', 20000), EchoHandler)
    for n in range(NWORKERS):
        t = Thread(target=serv.serve_forever)
        t.daemon = True
        t.start()
    serv.serve_forever()

3.创建UDP服务器

实现一个基于UDP协议的服务器来与客户端通信

from socketserver import BaseRequestHandler, UDPServer
import time

class TimeHandler(BaseRequestHandler):
    def handle(self):
        print('Got connection from', self.client_address)
        # Get message and client socket
        msg, sock = self.request
        resp = time.ctime()
        sock.sendto(resp.encode('ascii'), self.client_address) #连接成功 返回客户端地址信息

if __name__ == '__main__':
    serv = UDPServer(('', 20000), TimeHandler)
    serv.serve_forever()

>>> from socket import socket, AF_INET, SOCK_DGRAM
>>> s = socket(AF_INET, SOCK_DGRAM)
>>> s.sendto(b'', ('localhost', 20000))
0
>>> s.recvfrom(8192)
(b'Wed Aug 15 20:35:08 2012', ('127.0.0.1', 20000))
>>>

4.通过CIDR地址生成对应的IP地址集

有一个CIDR网络地址比如“123.45.67.89/27”,你想将其转换成它所代表的所有IP (比如,“123.45.67.64”, “123.45.67.65”, …, “123.45.67.95”))

CIDR网络地址比如“123.45.67.89/27” 表示前27位固定 剩余5位为掩码 则产生32个ip地址

>>> import ipaddress
>>> net = ipaddress.ip_network('123.45.67.64/27')
>>> net
IPv4Network('123.45.67.64/27')
>>> for a in net:
...     print(a)
...
123.45.67.64
123.45.67.65
123.45.67.66
123.45.67.67
123.45.67.68
...
123.45.67.95
>>>

>>> net6 = ipaddress.ip_network('12:3456:78:90ab:cd:ef01:23:30/125')
>>> net6
IPv6Network('12:3456:78:90ab:cd:ef01:23:30/125')
>>> for a in net6:
...     print(a)
...
12:3456:78:90ab:cd:ef01:23:30
12:3456:78:90ab:cd:ef01:23:31
12:3456:78:90ab:cd:ef01:23:32
12:3456:78:90ab:cd:ef01:23:33
12:3456:78:90ab:cd:ef01:23:34
12:3456:78:90ab:cd:ef01:23:35
12:3456:78:90ab:cd:ef01:23:36
12:3456:78:90ab:cd:ef01:23:37
>>>

5.通过XML-RPC实现简单的远程调用

想去执行运行在远程机器上面的Python程序中的函数或方法

实现一个远程方法调用的最简单方式是使用XML-RPC

from xmlrpc.server import SimpleXMLRPCServer

class KeyValueServer: #实现了键-值存储功能的简单服务器
    _rpc_methods_ = ['get', 'set', 'delete', 'exists', 'keys']
    def __init__(self, address):
        self._data = {}
        self._serv = SimpleXMLRPCServer(address, allow_none=True)
        for name in self._rpc_methods_:
            self._serv.register_function(getattr(self, name))

    def get(self, name):
        return self._data[name]

    def set(self, name, value):
        self._data[name] = value

    def delete(self, name):
        del self._data[name]

    def exists(self, name):
        return name in self._data

    def keys(self):
        return list(self._data)

    def serve_forever(self):
        self._serv.serve_forever()

# Example
if __name__ == '__main__':
    kvserv = KeyValueServer(('', 15000))
    kvserv.serve_forever()


>>> from xmlrpc.client import ServerProxy
>>> s = ServerProxy('http://localhost:15000', allow_none=True)
>>> s.set('foo', 'bar')
>>> s.set('spam', [1, 2, 3])
>>> s.keys()
['spam', 'foo']
>>> s.get('foo')
'bar'
>>> s.get('spam')
[1, 2, 3]
>>> s.delete('spam')
>>> s.exists('spam')
False
>>>

6.在不同的Python解释器之间交互

通过使用 multiprocessing.connection 模块可以很容易的实现解释器之间的通信

from multiprocessing.connection import Listener
import traceback

def echo_client(conn):
    try:
        while True:
            msg = conn.recv() #客户端发送请求
            conn.send(msg) 
    except EOFError:
        print('Connection closed')

def echo_server(address, authkey):
    serv = Listener(address, authkey=authkey) #服务端监听
    while True:
        try:
            client = serv.accept()

            echo_client(client)
        except Exception:
            traceback.print_exc()

echo_server(('', 25000), authkey=b'peekaboo')

7.在网络服务中加入SSL

实现一个基于sockets的网络服务,客户端和服务器通过SSL协议认证并加密传输的数据

from socket import socket, AF_INET, SOCK_STREAM
import ssl

KEYFILE = 'server_key.pem'   # 私钥
CERTFILE = 'server_cert.pem' # 权威证书

def echo_client(s): #客户端
    while True:
        data = s.recv(8192)
        if data == b'':
            break
        s.send(data)
    s.close()
    print('Connection closed')

def echo_server(address): #服务端
    s = socket(AF_INET, SOCK_STREAM)
    s.bind(address) #绑定地址后监听
    s.listen(1)

    # ssl协议封装
    s_ssl = ssl.wrap_socket(s,
                            keyfile=KEYFILE,
                            certfile=CERTFILE,
                            server_side=True
                            )
    #验证ssl协议成功后进行连接
    while True:
        try:
            c,a = s_ssl.accept()
            print('Got connection', c, a)
            echo_client(c) #连接成功后转入echo_client(s)处理 进行回复
        except Exception as e:
            print('{}: {}'.format(e.__class__.__name__, e))

echo_server(('', 20000))


>>> from socket import socket, AF_INET, SOCK_STREAM
>>> import ssl
>>> s = socket(AF_INET, SOCK_STREAM) #建立客户端套接字句柄
>>> s_ssl = ssl.wrap_socket(s,
                cert_reqs=ssl.CERT_REQUIRED,
                ca_certs = 'server_cert.pem') #请求ssl验证
>>> s_ssl.connect(('localhost', 20000)) #验证成功后连接
>>> s_ssl.send(b'Hello World?') #发送数据
12
>>> s_ssl.recv(8192) #回复数据
b'Hello World?'
>>>

8.发送与接收大型数组

注意:通过网络连接发送和接受连续数据的大型数组,并尽量减少数据的复制操作

def send_from(arr, dest):
    view = memoryview(arr).cast('B') #利用 memoryviews 来发送和接受大数组
    while len(view):
        nsent = dest.send(view)
        view = view[nsent:]

def recv_into(arr, source):
    view = memoryview(arr).cast('B')
    while len(view):
        nrecv = source.recv_into(view)
        view = view[nrecv:]

创建一个通过socket连接的服务器和客户端程序

(1)服务端

>>> from socket import *
>>> s = socket(AF_INET, SOCK_STREAM)
>>> s.bind(('', 25000))
>>> s.listen(1)
>>> c,a = s.accept()
>>>

(2)客户端

>>> from socket import *
>>> c = socket(AF_INET, SOCK_STREAM)
>>> c.connect(('localhost', 25000))
>>>

创建大型数组测试

# Server
>>> import numpy
>>> a = numpy.arange(0.0, 50000000.0)
>>> send_from(a, c)
>>>

# Client
>>> import numpy
>>> a = numpy.zeros(shape=50000000, dtype=float)
>>> a[0:10]
array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])
>>> recv_into(a, c)
>>> a[0:10]
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.])
>>>

你可能感兴趣的:(Python,服务器,python)