热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Python高级之网络编程及TCP/IP协议簇的OSI七层模型介绍

本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。

本节内容

  1. 网络通信概念
  2. socket编程
  3. socket模块一些方法
  4. 聊天socket实现
  5. 远程执行命令及上传文件
  6. socketserver及其源码分析

1.网络通信概念

说到网络通信,那就不得不说TCP/IP协议簇的OSI七层模型了,这个东西当初在学校都学烂了。。。(PS:毕竟本人是网络工程专业出身。。。) 简单介绍下七层模型从底层到上层的顺序:物理层(定义物理设备的各项标准),数据链路层(mac地址等其他东西的封装),网络层(IP包头的的封装),传输层(TCP/UDP数据报头的封装),会话层(这一层涉及的东西不多,但是我觉得SSL(安全套接字)应该封装在这一层,对于应用是透明的),表示层(数据的压缩解压缩放在这一层),应用层(这一层就是用户使用的应用了)

OSI的七层模型从上到下是一层一层封装的过程,一个数据从一台计算机到另一台计算机是先从上到下封装,之后传输到达另一台计算机之后是从下到上一层一层解封装的过程。

好了,说了这么多,那么我们开发里面涉及到的网络通信包含一些什么东西呢?首先我们程序开发中大部分所使用的协议是TCP协议(传输层)UDP协议涉及的比较少。网络层是IPV4协议,当然IPV6可能是未来的主流,还有一些其他网络协议这里并不涉及。。。SSL(安全套接字)可能在web应用中为了提供数据安全性用得比较多,但是服务端应用程序和程序之间的数据传输不会使用到ssl进行数据安全性的保护。所以,我们平常用的基于网络编程所使用的网络协议一般就是使用传输层的TCP协议,网络层的IPV4协议,更底层的协议。。。并不需要我们考虑,那些是网络设备之间该关心的事情。。。哈哈哈

那么,为什么要用TCP协议呢?因为TCP协议提供了一个面向连接的,稳定的通道,数据是按照顺序到达的,TCP协议的机制保证了TCP协议传输数据是一个可靠的传输。但是TCP协议也有他的缺点,那就是保证可靠传输所牺牲的代价就是速度比较慢(当然也不是很离谱,除非在某些极端情况下:比如传输大量的小数据)TCP之所以是面向连接的是因为它的三次握手以及四次挥手(太出名了,这里不用介绍了。。。),保障数据包按照顺序到达是通过分片编号实现的,每一个数据包都有一个编号,接收端根据这个编号去将接收的数据按原来数据顺序组装起来。当然,TCP协议之所以是一个可靠的传输和他的重传机制也是分不开的,当对方没有收到你发送的一个数据包的时候,TCP协议会重新传输这个数据包到对方,直到对方确认收到了这个数据包为止。。。。当然TCP协议里面还有很多优秀的东西。这里就不一一赘述了。哈哈,不然这里就成了网络专场了。。。

好了,现在确定了我们使用TCP/IP来进行网络通信,那么要实现通信需要知道对方机器的IP地址和端口号(当然,这里指的端口号一般是指TCP的端口号,从1-65535,其中,1024及之前的端口被定义为知名端口,最好不要使用)

2.socket编程

前面的第一节只是前戏,为了引出我们今天介绍的socket编程,这前戏做的也是挺累的,哈哈哈。

python中的socket是一个模块,使用这个内置模块能够让我们实现网络通信。其实在unix/linux一切皆文件的思想下,socket也可以看作是一个文件。。。python进行网络数据通信也可以理解为一个打开文件读写数据的操作,只不过这是一个特殊的操作罢了。接下来是一个关于socket通信的流程图:

python高级之网络编程

流程描述:

  1. 服务器根据地址类型(ipv4,ipv6)、socket类型、协议创建socket

  2. 服务器为socket绑定ip地址和端口号

  3. 服务器socket监听端口号请求,随时准备接收客户端发来的连接,这时候服务器的socket并没有被打开

  4. 客户端创建socket

  5. 客户端打开socket,根据服务器ip地址和端口号试图连接服务器socket

  6. 服务器socket接收到客户端socket请求,被动打开,开始接收客户端请求,直到客户端返回连接信息。这时候socket进入阻塞状态,所谓阻塞即accept()方法一直等到客户端返回连接信息后才返回,开始接收下一个客户端连接请求

  7. 客户端连接成功,向服务器发送连接状态信息

  8. 服务器accept方法返回,连接成功

  9. 客户端向socket写入信息(或服务端向socket写入信息)

  10. 服务器读取信息(客户端读取信息)

  11. 客户端关闭

  12. 服务器端关闭

3.socket模块一些方法

下面是socket模块里面提供的一些方法,让我们实现socke通信。

sk=socket.socket()

创建socket对象,这个时候可以指定两个参数,一个是family,另一个是type

family:AFINET(代表IPV4,默认参数),AFINET6(代表使用IPV6),AF_UNIX(UNIX文件系统通信)

type:SOCKSTREAM(TCP协议通信,默认参数),SOCKDGRAM(UDP协议通信) 默认不写的话,family=AFINET type=SOCKSTREAM

sk.bind(address)

sk.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

sk.listen(backlog)

开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。 backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5 这个值不能无限大,因为要在内核中维护连接队列

sk.setblocking(bool)

是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

sk.accept()

接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。

接收TCP 客户的连接(阻塞式)等待连接的到来

sk.connect(address)

连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

sk.connect_ex(address)

同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061

sk.close()

关闭套接字

sk.recv(bufsize[,flag])

接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

sk.recvfrom(bufsize[.flag])

与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。

sk.send(string[,flag])

将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。

sk.sendall(string[,flag])

将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

内部通过递归调用send,将所有内容发送出去。

sk.sendto(string[,flag],address)

将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。

sk.settimeout(timeout)

设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

sk.getpeername()

返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。

sk.getsockname()

返回套接字自己的地址。通常是一个元组(ipaddr,port)

sk.fileno()

套接字的文件描述符

4.聊天socket实现

好了,前戏做了那么多,到现在都还没写一行代码呢,接下来到了实战的步骤了。

 1 #server端实现:
 2 import socket  # 导入socket模块
 3 sk=socket.socket()  # 实例化socket对象
 4 address=("0.0.0.0",8000)  # 定义好监听的IP地址和端口,可以绑定网卡上的IP地址,但是生产环境中一般绑定0.0.0.0这样所有网卡上都能够接收并处理这个端口的数据了
 5 sk.bind(address)  # 绑定IP地址和端口
 6 sk.listen(5)  # 设定侦听开始并设定侦听队列里面等待的连接数最大为5
 7 
 8 while True:  # 循环,为了建立客户端连接
 9     conn,addr=sk.accept()  # conn拿到的是接入的客户端的对象,之后服务端和客户端通信都是基于这个conn对象进行通信,add获取的是连接的客户端的IP和端口
10     while True:  # 这个循环来实现相互之间聊天的逻辑
11         try:  # 为什么要使用try包裹这一块呢?因为在通信过程中客户端突然退出了的话,服务端阻塞在recv状态时将会抛出异常并终止程序,为了解决这个异常,需要我们自己捕获这个异常,这是在windows上,linux上不会抛出异常
12             data=conn.recv(1024)  # 定义接收的数据大小为1024个字节并接受客户端传递过来的数据,注意这里的数据在python3中是bytes类型的,在python3中网络通信发送和接收的数据必须是bytes类型的,否则会报错
13             if data:  # 假如客户端传递数据过来时
14                 print("-->",str(data,"utf-8"))  # 打印客户端传递过来的数据,需要从bytes类型数据解码成unicode类型的数据
15                 data=bytes(input(">>>"),"utf-8")  # 接收输入的数据并转换成bytes类型的数据
16                 conn.send(data)  # 将bytes类型的数据发送给客户端
17             else:  # 否则关闭这个客户端连接的对象,当客户端正常退出,执行了sk.close()时将不会发送数据到服务端,也就是说recv获取到的数据是空的
18                 conn.close()  # 这时关闭这个conn对象并退出当前循环等待下一个客户端对象来连接
19                 break
20         except ConnectionResetError as e:  # 捕获到异常之后,打印异常出来并退出循环等待下一个客户端连接
21             print(e)
22             break
23 
24 #client端实现
25 import socket  # 导入socket模块
26 sk=socket.socket()  # 实例化客户端对象
27 address=("127.0.0.1",8000)  # 设置客户端需要连接的服务端IP地址以及端口
28 sk.connect(address)  # 连接服务端的IP地址以及端口
29 while True:  # 循环实现对话
30     data=input(">>>").strip()  # 获取用户输入的数据
31     if data=="exit":  # 如果输入的是exit 关闭该对象并退出程序
32         sk.close()  # 关闭对象
33         break  # 退出循环
34     sk.send(bytes(data,"utf-8"))  # 发送刚输入的数据,要先转换成bytes类型的数据
35     data=str(sk.recv(1024),"utf-8")  # 接收服务端发送的数据,并将其转换成unicode数据类型
36     print("-->",data)  # 打印服务端传输过来的数据
显示代码
推荐阅读
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
  • python3+tkinter实践历程(四)——模仿CRT完成基于socket通信与tkinter的TCP串口客户端
    python3tkinter实践历程(四)——基于socket通信与tkinter的TCP串口客户端(仿CRT)文章目录系列文章目录分享背景制作背景最终功能工具截图展示代码详解系列 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了通过ABAP开发往外网发邮件的需求,并提供了配置和代码整理的资料。其中包括了配置SAP邮件服务器的步骤和ABAP写发送邮件代码的过程。通过RZ10配置参数和icm/server_port_1的设定,可以实现向Sap User和外部邮件发送邮件的功能。希望对需要的开发人员有帮助。摘要长度:184字。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • Oracle优化新常态的五大禁止及其性能隐患
    本文介绍了Oracle优化新常态中的五大禁止措施,包括禁止外键、禁止视图、禁止触发器、禁止存储过程和禁止JOB,并分析了这些禁止措施可能带来的性能隐患。文章还讨论了这些禁止措施在C/S架构和B/S架构中的不同应用情况,并提出了解决方案。 ... [详细]
  • 模块化区块链生态系统的优势概述及其应用案例
    本文介绍了相较于单体区块链,模块化区块链生态系统的优势,并以Celestia、Dymension和Fuel等模块化区块链项目为例,探讨了它们解决可扩展性和部署问题的方案。模块化区块链架构提高了区块链的可扩展性和吞吐量,并提供了跨链互操作性和主权可扩展性。开发人员可以根据需要选择执行环境,并获得奖学金支持。该文对模块化区块链的应用案例进行了介绍,展示了其在区块链领域的潜力和前景。 ... [详细]
  • 概述H.323是由ITU制定的通信控制协议,用于在分组交换网中提供多媒体业务。呼叫控制是其中的重要组成部分,它可用来建立点到点的媒体会话和多点间媒体会议 ... [详细]
author-avatar
-qone0_784
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有