我是靠谱客的博主 虚拟草丛,最近开发中收集的这篇文章主要介绍Python网络编程总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

声明:本篇文章系学习作用
目录:

  1. 网络编程简介
  2. MAC地址与IP地址
  3. 网络开发架构
  4. OSI七层协议
  5. TCP/UDP协议
  6. 代码记录

一、网络编程简介

网络编程可简单的看成对信息的发送到接收,中间传输为物理线路作用,网络编程编程最主要的作用即是在发送端把信息通过规定好的协议包装,在接收端按照规定好的协议解析,从而提取所需要的对应的消息,达到通信的目的。

二、MAC地址与IP地址:

1.地址性质不同:
MAC地址是物理地址,即唯一标识计算机的地址,在计算机出厂时已经在计算机上唯一编辑好的地址,用于识别计算机的唯一,是不可变地址;
IP地址是逻辑地址,又指互联网协议地址,译为网际协议地址。IP地址是IP协议提供的一种统一地址,它为互联网上的每一个网络和每一台主机分配一个逻辑地址。网上的即时通信软件在消息通信时所涉及的地址普遍为IP地址。
MAC地址犹如人们的身份证,是一个单位人的唯一标识,是不变的。而IP地址更类似于人的学号,系临时标识。

2.长度定义:
MAC地址是Enternet网卡上带的地址,长度为48位;IP地址目前主流长度为32位长度。IP地址与MAC地址通过ARP协议联系到一起。

3.IP地址:
IP地址遵循IP协议,IP协议也叫因特网协议。IP协议是为计算机网络相互连接进行通信的协议,在因特网中使连接到网上的所有计算机网络实现相互通信。起初以太网,分组交换网等之间并不能互通,不能互通的主要原因是因为它们所传送数据的基本单元“帧”的格式不同。IP协议实际上是一套由软件程序组成的协议软件,它把不同的“帧”统一转换成“IP数据报”格式,使得各种计算机都能在因特网 上实现互通。
IP地址是一个32位的二进制数,通常被分割为4个八位二进制数(四个字节)。IP地址通常用点分十进制表示成:a.b.c.d 的形式,其中a.b.c.d都是0~256(不含256)之间的十进制整数。例:点分十进制IP地址(100.4.5.6),实际上是32位二进制数(01100100.00000100.00000101.00000110)。

4.IP地址有ipv4与ipv6:
首先出现的为ipv4,上述介绍的IP地址即为ipv4,由于互联网的蓬勃发展,ipv4地址已经被分配殆尽。为了扩大地址空间,ipv6被定义。ipv6采用128位地址长度。
ipv4的范围:0.0.0.0-255.255.255.255
ipv6的范围:0:0:0:0:0:0 - FFFFFF:FFFFFF:FFFFFF:FFFFFF:FFFFFF:FFFFFF
子网掩码也是一个IP地址,它是一种用来指明一个IP地址的哪些标识的是主机所在的子网,以及哪些标识是主机的掩码。子网掩码不能单独存在,必须结合IP地址一起使用。子网掩码根据特定的计算方式可划分子网,判断两台机器在不在一个局域网内等作用。

5.局域网:
图源百度
局域网通过交换机连接而成,在同一个局域网内的机器由交换机负责通信,交换机只认识MAC地址,在局域网内交换机可完成广播,组播,单播功能。

广播:即在两台计算机需通信时,一台计算机通过寻找对应的MAC地址,将指令发送给交换机,交换机对局域网内的所有计算机进行广播寻找(对所有计算机发送寻找指令),只有对应的MAC地址的计算机会回复交换机,交换机再将回复消息发送给该寻找计算机,从而实现局域网通信。

组播:广播方式下,信息会发送到不需要该信息的计算机主机,从而浪费宽带资源,所以出现了组播。组播又称多目标广播、多播。它允许把所发消息传送给有可能的目的地中的一个经过选择的子集,从而发送地址信息,以此一来节省了宽带资源。

单播:即一对一通讯,点对点的网络连接。如果一台发送者同时给多个的接收者传输相同的数据,也必须相应的复制多份的相同数据包。如果有大量主机希望获得数据包的同一份拷贝时,将导致发送者负担沉重、延迟长、网络拥塞;为保证一定的服务质量需增加硬件和带宽。

局域网之间的通信由路由器完成,路由器提供一个网关IP,同一个局域网的所有机器共享一个网关。通过网关发送报文实现通信。局域网内的机器不能访问除了本局域网之外的其他内网IP地址。

三、网络开发架构

网络开发架构通常分为C/S架构与B/S架构

1.C/S架构:
CS即Client/Server(客户机/服务器)结构,C/S结构在技能上非常成熟,它的重要特征就是交互性强、拥有安全的存取形式、网络通信数量低、响应速度快、利于处置大量数据。可是这个结构的程序就是针对性开发,变更不够灵活,维护与管理的难度较大。常常只局限在小型局域网,不利于扩展。而且,因为这个结构的每台客户机全部须要安装相对应的客户端程序,分布功能弱并且兼容性差,不可以完成迅速部署安装与配置,因为这样缺少通用性,拥有比较大的局限性。请求拥有肯定专业水准的技能人员去结束。
BS即Browser/Server(浏览器/服务器)结构,就是只安装维护一个服务器(Server),而客户端选用浏览器(Browse)运行软件。B/S结构应用程序相对于传统的C/S结构应用程序就是一个特别大的进步。 B/S结构的重要特征就是分布性强、维护方便、开发简单并且共享性强、总体拥有费用低。但数据安全性问题、对服务器需要过高、数据传输速度慢、软件的个性化特征明显减少,这些缺点就是有目共睹的,难以完成传统形式下的特殊功能请求。比如通过浏览器实行大量的数据输入或实行报表的应答、专用性打印输出全部相对比较困难与不便。另外,完成复杂的应用构造有较大的困难。

2.优缺点分析:
(1)优点:
  ●可以足够表现客户端PC的处置才能,很多工作能够在客户端处置以后再提交给服务器,于是CS客户端响应速度快。
  ●操作界面漂亮、形式多样,能够足够满足客户自己的个性化要求。
  ●C/S结构的管理信息系统拥有比较强的事务处置才能,可以完成复杂的业务过程。
  ●安全性能能够非常容易确保,C/S通常面向相比固定的用户群,程序越发注重过程,它能够对权限实行多层次校验,提供了更安全的存取形式,对信息安全的控制才能非常强。通常高度机密的信息系统选用C/S结构适宜。

(2)缺点:
  ●须要专门的客户端安装程序,分布功能弱,针对点多面广且不具备网络条件的用户群体,不可以完成迅速部署安装与配置。
  ●兼容性差,关于不一样的开发工具,拥有比较大的局限性。假如选用不一样工具,须要重新改写程序。
  ●开发、维护费用较高,须要拥有肯定专业水准的技术人员才可以结束,发生一次升级,就全部客户端的程序全部须要更改。。
  ●用户群固定。因为程序须要安装就可使用,因为这样不符合面向一些不可知的用户,于是实用面窄,常常用来局域网中。
  
BS架构:
(1)优点:
  ●分布性强,客户端零维护。只需有网络、浏览器,能够随时随地实行查询、浏览等业务处理。
  ●业务扩展简单便利,通过添加网页就可以添加服务器功能。
  ●维护简单便利,只须要更改网页,就可以完成全部用户的同步更新。
  ●开发简单,共享性强。

(2)缺点:
  ●个性化特征明显减少,没办法完成拥有个性化的功能要求。
  ●在跨浏览器上,BS架构不尽如人意。
  ●客户端服务器端的交互就是请求-响应形式,常常动态刷新页面,响应速度明显减少(Ajax能够肯定程度上处理这个问题)。没办法完成分页显示,给数据库访问导致较大的压力。
  ●在速度与安全性上须要花费超大的设计费用。
  ●功能弱化,难以完成传统形式下的特殊功能需要。

小结:
CS响应速度快,安全性强,通常应用在局域网当中,可是开发维护费用高;BS能够完成跨平台,客户端零维护,可是个性化才能低,响应速度较慢。于是有一些单位平日办公应用BS,在实际生产当中使用CS结构。

四、OSI七层协议

OSI七层协议是一个开放性的通信系统互联参考模型,OSI7层从上到下分别为:
7:应用层
6:表示层
5:会话层
4:传输层
3:网络层
2:数据链路层
1:物理层

7、6、5、4层定义了程序的功能,3、2、1层通完成过网络的端到端,点到点的数据流。

在编程开发中通常用到的OSI五层协议

1.应用层:
应用层是与其他计算机进行通讯的一个应用,它是对应应用程序的通信服务。例如Python程序。

2.表示层:
这层也称为表示层,它定义了如何开始、控制、结束一个会话,包括对多个双向消息的控制和管理,以便在只完成连续消息的一部分时可以通知应用,从而表示层看到的数据是连续的。port,udp/tcp协议,四层路由器,四层交换机的工作在此。

3.网络层:
这层对端到端的包传输进行定义,它定义了能够标识所有节点的逻辑地址,还定义了路由实现的方式和学习方式。为了适应最大传输单元长度小于包长度的传输介质,网络层还定义了如何将一个包分解成更小的包的分段方法。ipv4,ipv6,路由器,三层交换机的工作在此。

4.数据链路层:
它定义了在单个链路上如何传输数据集。这些协议与被讨论的各种介质有关。这一层涉及到MAC地址,ARP协议,网卡,二层交换机。

5.OSI的物理层规范是有关传输介质的特性,这些规范通常也参考了其他组织制定的标准。连接头、帧、帧的使用、电流、编码及光调制等都属于各种物理层规范中的内容。物理层常用多个规范完成对所有细节的定义。

五、TCP/UDP协议

TCP和UDP协议是TCP/IP协议的核心,TCP传输协议属于传输层协议。其中TCP提供IP环境下的数据可靠传输。它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗的说它是事先为所发的数据开辟出连接好的通道,然后再进行数据发送;而UDP则不为IP提供可靠性、流控或差错恢复功能。一般来说,TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低,传输经济的应用。

1.传输控制协议TCP:
TCP(传输控制协议)定义了两台计算机之间进行可靠的传输而交换的数据和确认信息的格式,以及计算机为了确保数据的正确达到而采取的措施。TCP最大的特点就是提供了面向连接、可靠的字节流服务。例如语音连接/视频聊天等,还用于缓存高强电影/qq远程控制/发邮件等。

2.用户数据报协议UDP:
UDP(用户数据报协议)是一个简单的面向数据报的传输层协议。提供的是面向不可靠的数据流传输,UDP不提供可靠性,也不提供报文到达确认、排序及流量控制等功能,它只是把应用程序传给IP层的数据发送出去,但是不能保证它们能正确到达目的地。因此报文或许会丢失、重复以及乱序等。但由于UDP在传输数据报前不用在客户和服务器之间建立连接,且没有超时重发等机制,传输速度很快。例如在线播放视频/qq发消息/即时通信消息等。

总结:TCP需要先建立连接,然后才能通信,特点是可靠(消息不会丢失),消息相对安全,实时性高,但占用资源大,且速度慢;
UDP不需要建立连接即可通信,特点是不占用连接,少占用资源,发送速度很快,但也不可靠(因为网络不稳定会丢失)。

3.TCP的三次挥手与四次握手
三次握手图片源于百度
在发送端会发送一个带有SYN标志的数据包给接收方;
接收方接收后回传一个待以后SYN/ACK标志的数据包传递确认信息,表示我收到了;
最后,发送方在回传一个带有ACK标志的数据包,带表我知道了,表示握手结束。

图片源于百度

四次挥手
第一次挥手时,Client端发送一个FIN,用来关闭Client端到Server端的数据传送,Client端进入FIN_WAIT_1状态;
第二次挥手:Server端收到FIN后,发送一个ACK给Client端,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server端进入CLOSE_WAIT状态;
第三次挥手:Server端发送一个FIN,用来关闭Server端到Client端的数据传送,Server端进入LAST_ACK状态;
第四次挥手:Client端收到FIN后,Client端进入TIME_WAIT状态,接着发送一个ACK给Server端,确认序号为收到序号+1,Server端进入CLOSE状态,完成四次挥手

六、代码记录

接下来实现一个本地最简单的网络通信
涉及的Python Page有:socket模块
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯。

socket.socket ( family ,type ,proto)

参数family可设置AF_UNIX与AF_INET
socket.AF_INET IPv4(默认)
socket.AF_INET6 IPv6
socket.AF_UNIX 只能够用于单一的Unix系统进程间通信

socket_type可以是如下参数:
socket.SOCK_STREAM  流式socket , for TCP (默认)
socket.SOCK_DGRAM   数据报式socket , for UDP

proto默认为0,与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议

套件字对象内置方法:
服务器端套接字函数:
s.bind()   绑定地址(ip地址,端口)到套接字,参数必须是元组的格式例如:
s.bind((‘127.0.0.1’,8009))
s.listen(5)  开始监听,5为最大挂起的连接数
s.accept()  被动接受客户端连接,阻塞,等待连接客户端套接字函数
s.connect()  连接服务器端,参数必须是元组格式例如:
s.connect((‘127,0.0.1’,8009))
公共用途的套接字函数
s.recv(1024)  接收TCP数据,1024为一次数据接收的大小
s.send(bytes)  发送TCP数据,python3发送数据的格式必须为bytes格式
s.sendall()  完整发送数据,内部循环调用send
s.close()  关闭套接字

一个简单的本地网络通信就写好了:
在这里插入图片描述
运行效果:
在这里插入图片描述
在这里插入图片描述

通过TCP协议写一个服务端与多个客户端通信的例子:
建立一个Python Package文件,文件中添加server,client Python模块。代码如下:

server端代码:

import socket

sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()

while True:
    # 在此使用while True则是给conn接收多个客户端连接
    conn, addr = sk.accept()
    while True:
        # 在此使用while True则是与一个客户端进行无限发送消息
        send_msg = input(">>>")
        conn.send(send_msg.encode('gbk'))
        # 停止聊天
        if send_msg.upper() == 'Q':
            break
        msg = conn.recv(2048).decode('gbk')
        if msg.upper() == 'Q': break
        print(msg)
    conn.close()

sk.close()

client端代码:

import socket

sk = socket.socket()

sk.connect(('127.0.0.1', 9000))
while True:
    msg = sk.recv(2048).decode('gbk')
    if msg.upper() == 'Q': break
    print(msg)
    send_msg = input(">>>")
    sk.send(send_msg.encode('gbk'))
    if send_msg.upper() == 'Q':
        break

sk.close()

在这里插入图片描述
运行结果:
此时打开两个客户端
在这里插入图片描述
与客户端1占线通信,由于TCP协议是建立连接通信,所以是服务端客户端一对一的
在这里插入图片描述
所以客户端2是正在等待客户端1与服务端断开连接时在与服务端通信,处于等待阶段
在这里插入图片描述
当服务端与客户端1某单方面停止通信,关闭连接后,客户端1程序结束
在这里插入图片描述
在这里插入图片描述
此时正在等待客户端1结束与服务端连接的客户端2与服务端建立连接
在这里插入图片描述
在这里插入图片描述
TCP协议建立的网络通信例子到此结束。

接下来使用UDP协议建立的服务端与客户端程序例子:
建立一个Python Package文件,文件中添加server,client Python模块。代码如下

server端代码

import socket

# udp协议需将type属性设置为socket.SOCK_DGRAM
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1', 9001))
server_name = "服务器:".encode('gbk')
while True:
    msg, addr = sk.recvfrom(2048)
    print(msg.decode('gbk'))
    send_info = input(">>>")
    sk.sendto(server_name + send_info.encode('gbk'), addr)

client端代码

import socket

sk = socket.socket(type=socket.SOCK_DGRAM)
server = ('127.0.0.1', 9001)
ider_number = 0
while True:
    ider_number += 1
    if ider_number == 1:
        ider_info = input(">>>请设置你的名字:")
        ider_info = ider_info.encode('gbk') + ":".encode('gbk')
    else:
        send_info = input(">>>")
        if send_info.upper() == 'Q': break
        send_info = send_info.encode('gbk')
        sk.sendto(ider_info + send_info, server)
        msg = sk.recv(2048).decode('gbk')
        if msg[4].upper() == 'Q': break
        print(msg)

在这里插入图片描述
并开启服务端与一个客户端:
在这里插入图片描述
在这里插入图片描述

OK,已经建立了通信,接下来打开第二个客户端:
在这里插入图片描述
此时在客户端1未关闭的情况下新开启的客户端2仍可以和服务端同时建立连接
在这里插入图片描述
在这里插入图片描述
一对多连接成功建立,这就是基于UDP协议所建立的连接

知道了两种协议的连接后,简单使用TCP协议去发送文件:

server端代码如下:

import socket
import json
# 接受

sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()

conn, _ = sk.accept()
msg = conn.recv(2048).decode('gbk')
msg = json.loads(msg)

with open(msg['filename'], 'wb') as f:
    content = conn.recv(msg['filesize'])
    print("-->", len(content))
    f.write(content)

conn.close()
sk.close()

client端代码如下:

import socket
import json
import os
# 发送

sk = socket.socket()
sk.connect(('127.0.0.1', 9000))

abs_path = r'F:fileclass_filePython folderPython网络编程temp'
file_name = os.path.basename(abs_path)
file_size = os.path.getsize(abs_path)
dic = {'filename':file_name, 'filesize':file_size}
str_dic = json.dumps(dic)
sk.send(str_dic.encode('gbk'))

with open(abs_path, mode='rb') as f:
    content = f.read()
    sk.send(content)

sk.close()

在这里插入图片描述
随意写一份文本文件,在此我用随手笔记做代替
在这里插入图片描述
将该文件放置在与Python package同级别的目录下,若发送成功则文件会发送至Python package目录(即6基于tcp协议的文件传输目录)下
在这里插入图片描述
在开启server端与client端后
在这里插入图片描述

已然发送成功

粘包现象
什么粘包?
两条或更多条分开发送的信息连在一起就是粘包现象
发生在发送端 : 发送间隔短,数据小,由于优化机制就合并在一起发送了
发生在接收端 : 接收不及时,所以数据就在接收方的缓存端黏在一起了
粘包发生的本质 : tcp协议的传输是流式传输 数据与数据之间没有边界
怎么解决粘包 : 自定义协议 struct模块
先发送四字节的数据长度,先接受4字节 知道数据的长度
再按照长度发送数据,再按照长度接收数据

粘包代码展示:
server端

import socket

sk = socket.socket()
sk.bind(("127.0.0.1", 9001))
sk.listen()

conn,addr = sk.accept()
# 粘包现象
conn.send(b"hello")
conn.send(b"word")

conn.close()
sk.close()

client端

import socket
import time

sk = socket.socket()
sk.connect(("127.0.0.1", 9001))
time.sleep(0.1)
msg = sk.recv(1024)
print(msg)      
msg2 = sk.recv(1024)
print(msg2)

在这里插入图片描述
运行结果如下:
在这里插入图片描述
两条消息粘在了一起

问题的根源在于,接收端不知道发送端将要传送的字节流的长度
解决办法是,可以借助一个模块,这个模块可以把要发送的数据长度转换成固定长度的字节
这样客户端每次接收消息之前只要先接受这个固定长度字节的内容看一看接下来要接收的信息大小
那么最终接受的数据只要达到这个值就停止,就能刚好不多不少的接收完整的数据了
发送时:先发送 struct 转换好的数据长度 4 字节,再发送数据
接收时:先接受 4 个字节使用 struct 转换成数字来获取要接收的数据长度,再按照长度接收数据 |

解决方案struct模块
server端代码

import struct
import socket

sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()

conn, addr = sk.accept()
send_msg = input('>>>').encode()
# 注意这里是用len()来代表字节长度
bytes_len = struct.pack('i', len(send_msg))
conn.send(bytes_len)
conn.send(send_msg)
conn.send(b'world')

conn.close()
sk.close()

client端代码

import struct
import socket

sk = socket.socket()
sk.connect(('127.0.0.1', 9000))

# 接收固定长度的内容
bytes_len = sk.recv(4)
# 这里接收到的是一个元组,因此要设置索引来得到想要的结果
msg_len = struct.unpack('i', bytes_len)[0]
msg = sk.recv(msg_len)
print(msg.decode())

msg2 = sk.recv(5)
print(msg2)
sk.close()

在这里插入图片描述
先后运行server端与client端结果如下:
在这里插入图片描述
在这里插入图片描述
粘包现象解决

由于本人编程水平不足,许多部分也是从其他博主学习而来,本文仅起学习交流作用。若有朋友看见错误请及时指出,你对本人的点拨本人会铭记于心!感谢观看。

文章到此结束,学习路上共勉!

最后

以上就是虚拟草丛为你收集整理的Python网络编程总结的全部内容,希望文章能够帮你解决Python网络编程总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部