Python-100days-14

Day14 - 网络编程入门

计算机基础

mark一本《计算机网络》书籍

计算机网络发展史

TCP/IP模型

协议,就是通信计算机双方必须共同遵守的一组约定,网络协议三要素:语法、语义、时序。协议族,就是一系列的协议及其构成的通信模型,我们通常把这套东西成为TCP/IP模型。与国际标准化组织发布的OSI/RM七层模型不同,TCP/IP只是一个四层模型,自下而上依次是:网络接口层、网络层、传输层、应用层。


image.png

IP,常被翻译为网际协议,它服务于网络层,主要实现寻址和路由的功能。接入网络的每一台及其都要有自己的IP地址,IP地址就是主机在计算机网络上的身份标识。由于IPv4地址匮乏,我们平常使用IP地址并不是全球唯一的IP地址,而是一个局域网中的内部IP地址,通过网络地址转换服务我们也可以实现对网络的访问。计算机网络有大量被我们称为“路由器”的中继设备,它们会存储转发我们发送到网络上的数据分组,让从源头发出的数据最终能够找到传送到的目的地通路,这项功能就是所谓的路由。
TCP全称是传输控制协议,它是基于IP提供的寻址和路由服务而建立起来的负责实现端到端可靠传输的协议,之所以将TCP成为可靠的传输协议是因为TCP向调用者承诺了三件事:

  • 数据不传丢不传错(利用握手,校验,重传机制)
  • 流量控制(通过窗口活动匹配数据发送者和接受者之间的传输速度)
  • 拥塞控制(通过RTT时间以及对滑动窗口的控制缓解网络拥堵)
网络应用模式
  • C/S和B/S模式,即通过客户端到服务器,或者浏览器到服务器,进行网络访问。
  • 去中心化的网络应用模式。意思就是去中心化的网络应用通常没有固定的服务器或者固定的客户端,所有应用的使用者既可以作为资源的提供者也可以作为资源的访问者。

基于HTTP协议的网络资源访问

HTTP超文本传输协议

HTTP是一种用于分布式、协作式和超媒体信息系统的应用层协议,它是万维网数据通信的基础,设计HTTP最初目的是为了提供一种发布和接受HTML页面的方法,通过HTTP或者HTTPS(超文本传输安全协议)请求的资源由URL(统一资源标识符)来标识。

ps.有空翻翻,Mark一篇博客《HTTP协议入门》
JSON格式

json是一种轻量级的数据交换语言,为了让人容易阅读的基础上,用来传输由属性值或者序列性的值组成的数据对象。

requests库

requests 是一个基于HTTP协议来使用网络的第三方库,它可以很方便使用HTTP,避免安全缺陷、冗余代码以及重复造轮子。
敲一个例子,下载图片

from time import time
from threading import Thread
import requests

class DownloadHanlder(Thread):

    def __init__(self, url):
        super().__init__()
        self.url = url

    def run(self):
        # rfind 返回字符串最后一次出现的位置,从右向左查询,没有匹配到则返回-1
        filename = self.url[self.url.rfind('/') + 1:]
        print(filename)
        resp = requests.get(self.url)
        with open('data/' + filename, 'wb') as f:
            f.write(resp.content)

def main():
    resp = requests.get(
        'http://api.tianapi.com/meinv/?key=19f7261742115ad6d5656318d2c4b778&num=10')

    data_model = resp.json()
    for mm_dict in data_model['newslist']:
        url = mm_dict['picUrl']
        DownloadHanlder(url).start()

if __name__ == '__main__':
    main()

基于传输层协议的套接字编程

套接字就是一套用C语言携程的应用程序开发库,主要用于实现进程间的通信和网络编程,在网络应用开发中被广泛使用。在Python中也可以基于套接字来使用传输层提供的传输服务,并基于此开发自己的网络应用。实际开发中使用的套接字分三类:流套接字(TCP套接字)、数据报套接字和原始套接字。

TCP套接字

TCP套接字就是使用TCP协议提供的传输服务来实现网络通信的编程接口。在Python中可通过创建socket对象并指定type属性为SOCK_STREAM来使用TCP套接字。由于一台主机可有多个IP地址,而且很可能会配置多个不同服务,所以作为服务器端的程序,需要在创建套接字对象后将其绑定到指定的IP地址和端口上。
实现一个提供时间日期的服务器(注释代码很详细就不删掉了)

from socket import socket, SOCK_STREAM, AF_INET
from datetime import datetime

def main():
    # 1.创建套接字对象并指定使用哪种传输服务
    # family=AF_INET - IPv4地址
    # family=AF_INET6 - IPv6地址
    # type=SOCK_STREAM - TCP套接字
    # type=SOCK_DGRAM - UDP套接字
    # type=SOCK_RAW - 原始套接字
    server = socket(family=AF_INET, type=SOCK_STREAM)
    # 2.绑定IP地址和端口(端口用于区分不同的服务)
    # 同一时间在同一个端口上只能绑定一个服务否则报错
    server.bind(('192.168.1.2', 6789))
    # 3.开启监听 - 监听客户端连接到服务器
    # 参数512可以理解为连接队列的大小
    server.listen(512)
    print('服务器启动开始监听...')
    while True:
        # 4.通过循环接收客户端的连接并作出相应的处理(提供服务)
        # accept方法是一个阻塞方法如果没有客户端连接到服务器代码不会向下执行
        # accept方法返回一个元组其中的第一个元素是客户端对象
        # 第二个元素是连接到服务器的客户端的地址(由IP和端口两部分构成)
        client, addr = server.accept()
        print(str(addr) + '连接到了服务器.')
        # 5.发送数据
        client.send(str(datetime.now()).encode('utf-8'))
        # 6.断开连接
        client.close()

if __name__ == '__main__':
    main()

实现客户端

from socket import socket

def main():
    # 1.创建套接字对象默认使用IPv4和TCP协议
    client = socket()
    # 2.连接到服务器(需要指定IP地址和端口)
    client.connect(('192.168.1.2', 6789))
    # 3.从服务器接收数据
    print(client.recv(1024).decode('utf-8'))
    client.close()

if __name__ == '__main__':
    main()

上述例子没有使用多线程或者异步I/O的处理方式,只能一个一个客户执行。
下面设计一个多线程处理多用户请求的服务器,服务器向用户发送一张图片。

from socket import socket, SOCK_STREAM, AF_INET
from base64 import b64encode
from json import dumps
from threading import Thread


def main():
    # 自定义线程类
    class FileTransferHandler(Thread):

        def __init__(self, cclient):
            super().__init__()
            self.cclient = cclient

        def run(self):
            my_dict = {}
            my_dict['filename'] = '131.jpg'
            # JSON是纯文本不能携带二进制数据
            # 所以图片的二进制数据要处理成base64编码
            my_dict['filedata'] = data
            # 通过dumps函数将字典处理成JSON字符串
            json_str = dumps(my_dict)
            # 发送JSON字符串
            self.cclient.send(json_str.encode('utf-8'))
            self.cclient.close()

    # 1.创建套接字对象并指定使用哪种传输服务
    server = socket()
    # 2.绑定IP地址和端口(区分不同的服务)
    server.bind(('127.0.0.1', 5566))
    # 3.开启监听 - 监听客户端连接到服务器
    server.listen(512)
    print('服务器启动开始监听...')
    with open('131.jpg', 'rb') as f:
        # 将二进制数据处理成base64再解码成字符串
        data = b64encode(f.read()).decode('utf-8')
    while True:
        client, addr = server.accept()
        # 启动一个线程来处理客户端的请求
        FileTransferHandler(client).start()

if __name__ == '__main__':
    main()

客户端

from socket import socket
from json import loads
from base64 import b64decode

def main():
    client = socket()
    client.connect(('127.0.0.1', 5566))
    # 定义一个保存二进制数据的对象
    in_data = bytes()
    # 由于不知道服务器发送的数据有多大每次接收1024字节
    data = client.recv(1024)
    while data:
        # 将收到的数据拼接起来
        in_data += data
        data = client.recv(1024)
    # 将收到的二进制数据解码成JSON字符串并转换成字典
    # loads函数的作用就是将JSON字符串转成字典对象
    my_dict = loads(in_data.decode('utf-8'))
    filename = my_dict['filename']
    filedata = my_dict['filedata'].encode('utf-8')
    with open('data/' + filename, 'wb') as f:
        # 将base64格式的数据解码成二进制数据并写入文件
        f.write(b64decode(filedata))
    print('图片已保存.')

if __name__ == '__main__':
    main()

地址改成127.0.0.1,否则会报下面的错误。没搞清楚为啥。

OSError: [WinError 10049] 在其上下文中,该请求的地址无效。
ps.JSON并不能携带二进制数据,因此对图片的二进制数据进行了Base64编码的处理。Base64是一种用64个字符表示所有二进制数据的编码方式,通过将二进制数据每6位一组的方式重新组织,刚好可以使用0~9的数字、大小写字母以及“+”和“/”总共64个字符表示从000000到111111的64种状态。
UDP套接字

UDP,即用户数据报协议。TCP和UDP都是提供端到端传输服务的协议。UDP不对传输的可靠性和可达性做出任何承诺从而避免了TCP中握手和重传的开销,所以在强调性能和不要求数据完整性的场景中(例如传输网络音视频数据),UDP可能是更好的选择。

网络应用开发

发送电子邮件

发送邮件使用的是SMTP(简单邮件传输协议),SMTP是建立在TCP提供的可靠数据传输服务的基础上的应用级协议,它规定邮件的发送者如何跟发送邮件的服务器进行通信的细节,而Python中的smtplib模块将这些操作简化成几个函数。
利用Python发送邮件,可以参考菜鸟教程的文章很详细。《Python SMTP发送邮件》

发送短信

发送短信,其实就是看使用的短信平台提供的API,根据API写代码就完事了。
mark一下示例,用到的时候会写就完事了。

import urllib.parse
import http.client
import json

def main():
    host  = "106.ihuyi.com"
    sms_send_uri = "/webservice/sms.php?method=Submit"
    # 下面的参数需要填入自己注册的账号和对应的密码
    params = urllib.parse.urlencode({'account': '你自己的账号', 'password' : '你自己的密码', 'content': '您的验证码是:147258。请不要把验证码泄露给其他人。', 'mobile': '接收者的手机号', 'format':'json' })
    print(params)
    headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
    conn = http.client.HTTPConnection(host, port=80, timeout=30)
    conn.request('POST', sms_send_uri, params, headers)
    response = conn.getresponse()
    response_str = response.read()
    jsonstr = response_str.decode('utf-8')
    print(json.loads(jsonstr))
    conn.close()

if __name__ == '__main__':
    main()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 文章首发于个人blog欢迎指正补充,可联系lionsom_lin@qq.com原文地址:《网络是怎样连接的》阅读整...
    lionsom_lin阅读 14,107评论 6 31
  • 一、什么是TCP/IP 网络和协议 1. TCP/IP是一类协议系统,它是一套支持网络通信的协议集合。网络是计算机...
    karlon的马甲阅读 6,501评论 1 24
  • 网络编程 一.楔子 你现在已经学会了写python代码,假如你写了两个python文件a.py和b.py,分别去运...
    go以恒阅读 1,982评论 0 6
  • 第一章 TCP/IP简介 基本的C/S服务模型 网络编程是指编写的网络通信程序可以与网络上的其他程序进行通信。 T...
    Waldo_cuit阅读 1,910评论 0 6
  • 话说两台电脑要通讯就必须遵守共同的规则,就好比两个人要沟通就必须使用共同的语言一样。一个只懂英语的人,和一个只懂中...
    哲逗年阅读 888评论 0 0