python的网络编程

简介:

一、系统和网络

1、系统

操作系统: (Operating System,简称OS)是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。

2、osi七层协议

osi七层:

    物理层

    数据链路层

    网络层

    传输层

    会话层

    表示层

    应用层

tcp/ip五层:

    物理层

    数据链路层

    网络层

    传输层

    应用层

tcp/ip四层:

    网络接口层

    网络层

    传输层

    应用层


3、数据链路层

以太网协议:

       # 一组电信号构成一个数据包,叫做‘帧’

       # 每一数据帧分成:报头head和数据data两部分


head包含:(固定18个字节)

        发送者/源地址,6个字节

        接收者/目标地址,6个字节

        数据类型,6个字节

data包含:(最短46字节,最长1500字节)


数据包的具体内容:

head长度+data长度=最短64字节,最长1518字节,超过最大限制就分片发送


4、网络层

ip数据包也分为head和data部分

  head:长度为20到60字节

  data:最长为65,515字节

而以太网数据包的”数据”部分,最长只有1500字节。因此,如果IP数据包超过了1500字节,它就需要分割成几个以太网数据包,分开发送了。


5、传输层

tcp  三次握手.png

二、socket

1、介绍

socket图例.png

我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。

2、 套接字工作流程

套接字工作流程.png


服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束

3、套接字函数

#1、服务端套接字函数

s.bind()    绑定(主机,端口号)到套接字

s.listen()  开始TCP监听

s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来

#2、客户端套接字函数

s.connect()     主动初始化TCP服务器连接

s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

#3、公共用途的套接字函数

s.recv()            接收TCP数据

s.send()            发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)

s.sendall()         发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)

s.recvfrom()        接收UDP数据

s.sendto()          发送UDP数据

s.getpeername()     连接到当前套接字的远端的地址

s.getsockname()     当前套接字的地址

s.getsockopt()      返回指定套接字的参数

s.setsockopt()      设置指定套接字的参数

s.close()           关闭套接字

#4、面向锁的套接字方法

s.setblocking()     设置套接字的阻塞与非阻塞模式

s.settimeout()      设置阻塞套接字操作的超时时间

s.gettimeout()      得到阻塞套接字操作的超时时间

#5、面向文件的套接字的函数

s.fileno()          套接字的文件描述符

s.makefile()        创建一个与该套接字相关的文件


4、实现基于TCP的套接字(先启动服务端)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#服务端:
import  socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #tcp协议
phone.bind(( '127.0.0.1' , 8081 ))       #绑定ip和端口,让客户端连接
phone.listen( 5 )                 #半连接池大小
print ( 'starting...' )
conn,client_addr = phone.accept()      #等待客户端连接
print (conn,client_addr)
data = conn.recv( 1024 )              #基于建立好的conn链接对象收发消息
conn.send(data.upper())
conn.close()                    #断开链接
phone.close()                    #终止服务
#客户端:
import  socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #tcp协议
phone.connect(( '127.0.0.1' , 8081 ))         #连接服务器的ip和端口
phone.send( 'hello' .encode( 'utf-8' ))
data = phone.recv( 1024 )
print (data)
phone.close()

5、最终版基于TCP的套接字

上面的值实现发送一条消息和连接一个客户端,所以要对程序进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#服务端:
import  socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #tcp协议
phone.bind(( '127.0.0.1' , 8081 ))                  #绑定ip和端口,让客户端连接
phone.listen( 5 )                           #半连接池大小
while  True :
     conn,client_addr = phone.accept()            #等待客户端连接
     print (conn,client_addr)
     while  True :
         data = conn.recv( 1024 )               #基于建立好的conn链接对象收发消息
         conn.send(data.upper()) 
     conn.close()                        #断开链接
phone.close()                            #终止服务
#客户端:
import  socket
phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM)  #tcp协议
phone.connect(( '127.0.0.1' , 8081 ))         #连接服务器的ip和端口
while  True :
     msg = input ( '>>: ' ).strip()
     if  len (msg)  = =  0 : continue
     phone.send(msg.encode( 'utf-8' ))
     data = phone.recv( 1024 )
     print (data)
phone.close()

6、粘包

应用程序所看到的数据是一个整体,或说是一个流(stream),一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现粘包问题的原因。

所谓粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。

此外,发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一个TCP段。

若连续几次需要send的数据都很少,通常TCP会根据优化算法把这些数据合成一个TCP段后一次发送出去,这样接收方就收到了粘包数据。

7、解决粘包的处理方法

程序流程:客户端发送命令,服务端在本地执行后,返回得到的结果给客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 服务端:
from  socket  import  *
import  subprocess
import  struct
server = socket(AF_INET,SOCK_STREAM)
server.bind(( '127.0.0.1' , 8088 ))
server.listen( 5 )
while  True :
     conn,client_addr = server.accept()
     print (client_addr)
     while  True :
         try :
             cmd = conn.recv( 8096 )
             if  not  cmd: break
             obj = subprocess.Popen(cmd.decode( 'utf-8' ),shell = True ,
                              stdout = subprocess.PIPE,
                              stderr = subprocess.PIPE
                              )
             stdout = obj.stdout.read()
             stderr = obj.stderr.read()
             total_size  =  len (stdout)  +  len (stderr)      #制作固定长度的报头
             headers = struct.pack( 'i' ,total_size)
             conn.send(headers)
             conn.send(stdout)                         #发送命令的执行结果
             conn.send(stderr)
         except  ConnectionResetError:
             break
     conn.close()
server.close()
# 客户端:
from  socket  import  *
import  struct
client = socket(AF_INET,SOCK_STREAM)
client.connect(( '127.0.0.1' , 8088 ))
while  True :
     cmd = input ( '>>: ' ).strip()
     if  not  cmd: continue
     client.send(cmd.encode( 'utf-8' ))    #发送命令
     headers = client.recv( 4 )        #先接收命令长度,struct模块生成一个4个字节的结果
     total_size  =  struct.unpack( 'i' , headers)[ 0 ]
     recv_size = 0                 #再收命令的结果
     data = b''
     while  recv_size < total_size:
         recv_data = client.recv( 1024 )
         data + = recv_data
         recv_size + = len (recv_data)
     print (data.decode( 'gbk' ))
client.close()

8、解决粘包的处理方法加强版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#服务端:
from  socket  import  *
import  subprocess
import  struct
import  json
server = socket(AF_INET,SOCK_STREAM)
server.bind(( '127.0.0.1' , 8093 ))
server.listen( 5 )
while  True :
     conn,client_addr = server.accept()
     print (client_addr)
     while  True :
         try :
             cmd = conn.recv( 8096 )
             if  not  cmd: break
             obj = subprocess.Popen(cmd.decode( 'utf-8' ),shell = True ,
                              stdout = subprocess.PIPE,
                              stderr = subprocess.PIPE
                              )
             stdout = obj.stdout.read()
             stderr = obj.stderr.read()
             headers  =  {                                         #制作报头
                 'filepath' 'a.txt' ,
                 'md5' '123sxd123x123' ,
                 'total_size' len (stdout)  +  len (stderr)
             }
             headers_json  =  json.dumps(headers)                 #把headers转为json格式
             headers_bytes  =  headers_json.encode( 'utf-8' )      #前面的json结果得到字节形式
             conn.send(struct.pack( 'i' , len (headers_bytes)))     #先发报头的长度
             conn.send(headers_bytes)                           #发送报头
             conn.send(stdout)                                  #发送真实数据,正确的stdout,错误的stderr
             conn.send(stderr)
         except  ConnectionResetError:
             break
     conn.close()
server.close()
#客户端:
from  socket  import  *
import  struct
import  json
client = socket(AF_INET,SOCK_STREAM)
client.connect(( '127.0.0.1' , 8093 ))
while  True :
     cmd = input ( '>>: ' ).strip()
     if  not  cmd: continue
     client.send(cmd.encode( 'utf-8' ))
     headers_size = struct.unpack( 'i' ,client.recv( 4 ))[ 0 ]
     headers_bytes = client.recv(headers_size)
     headers_json = headers_bytes.decode( 'utf-8' )
     headers_dic = json.loads(headers_json)
     print ( '========>' ,headers_dic)
     total_size = headers_dic[ 'total_size' ]
     recv_size = 0
     data = b''
     while  recv_size < total_size:
         recv_data = client.recv( 1024 )
         data + = recv_data
         recv_size + = len (recv_data)
     print (data.decode( 'gbk' ))
client.close()

9、文件下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#服务端
import  socket
import  os
import  json
import  struct
SHARE_DIR = r 'F:\SHARE'           #目标文件路径
class  FtpServer:
     def  __init__( self ,host,port):
         self .host = host
         self .port = port
         self .server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
         self .server.bind(( self .host, self .port))
         self .server.listen( 5 )
     def  serve_forever( self ):
         print ( 'server starting...' )
         while  True :
             self .conn, self .client_addr = self .server.accept()
             print ( self .client_addr)
             while  True :
                 try :
                     data = self .conn.recv( 1024 )   #params_json.encode('utf-8')
                     if  not  data: break
                     params = json.loads(data.decode( 'utf-8' ))  #params=['get','a.txt']
                     cmd = params[ 0 ]
                     if  hasattr ( self ,cmd):
                         func = getattr ( self ,cmd)
                         func(params)
                     else :
                         print ( '\033[45mcmd not exists\033[0m' )
                 except  ConnectionResetError:
                     break
             self .conn.close()
         self .server.close()
     def  get( self ,params):  #params=['get','a.txt']
         filename = params[ 1 #filename='a.txt'
         filepath = os.path.join(SHARE_DIR,filename)
         if  os.path.exists(filepath):
             headers  =  {                                            #制作报头
                 'filename' : filename,
                 'md5' '123sxd123x123' ,
                 'filesize' : os.path.getsize(filepath)
             }
             headers_json  =  json.dumps(headers)
             headers_bytes  =  headers_json.encode( 'utf-8' )
             self .conn.send(struct.pack( 'i' , len (headers_bytes)))   #先发报头的长度
             self .conn.send(headers_bytes)                         #发送报头
             with  open (filepath, 'rb' ) as f:                      #发送真实的数据
                 for  line  in  f:
                     self .conn.send(line)
     def  put( self ):
         pass
if  __name__  = =  '__main__' :
     server = FtpServer( '127.0.0.1' , 8081 )
     server.serve_forever()
##客户端
import  socket
import  struct
import  json
import  os
DOWNLOAD_DIR = r 'F:\DOWNLOAD'     #下载路径
class  FtpClient:
     def  __init__( self ,host,port):
         self .host = host
         self .port = port
         self .client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
         self .client.connect(( self .host, self .port))
     def  interactive( self ):
         while  True :
             data = input ( '>>: ' ).strip()  #get a.txt
             if  not  data: continue
             params = data.split()  #parmas=['get','a.txt']
             cmd = params[ 0 #cmd='get'
             if  hasattr ( self ,cmd):
                 func = getattr ( self ,cmd)
                 func(params)  #func(['get','a.txt'])
     def  get( self ,params):
         params_json = json.dumps(params)
         self .client.send(params_json.encode( 'utf-8' ))
         headers_size  =  struct.unpack( 'i' self .client.recv( 4 ))[ 0 ]    #接收报头长度
         headers_bytes  =  self .client.recv(headers_size)          #接收报头
         headers_json  =  headers_bytes.decode( 'utf-8' )
         headers_dic  =  json.loads(headers_json)
         # print('========>', headers_dic)
         filename  =  headers_dic[ 'filename' ]
         filesize  =  headers_dic[ 'filesize' ]
         filepath  =  os.path.join(DOWNLOAD_DIR, filename)
         with  open (filepath,  'wb' ) as f:                    #接收真实数据
             recv_size  =  0
             while  recv_size < filesize:
                 line  =  self .client.recv( 1024 )
                 recv_size  + =  len (line)
                 f.write(line)
             print ( '===>下载成功' )
if  __name__  = =  '__main__' :
     client = FtpClient( '127.0.0.1' , 8081 )
     client.interactive()





本文转自 宋鹏超 51CTO博客,原文链接:http://blog.51cto.com/qidian510/2066654,如需转载请自行联系原作者

相关文章
|
15天前
|
机器学习/深度学习 人工智能 算法
猫狗宠物识别系统Python+TensorFlow+人工智能+深度学习+卷积网络算法
宠物识别系统使用Python和TensorFlow搭建卷积神经网络,基于37种常见猫狗数据集训练高精度模型,并保存为h5格式。通过Django框架搭建Web平台,用户上传宠物图片即可识别其名称,提供便捷的宠物识别服务。
189 55
|
1月前
|
Python
Python中的异步编程:使用asyncio和aiohttp实现高效网络请求
【10月更文挑战第34天】在Python的世界里,异步编程是提高效率的利器。本文将带你了解如何使用asyncio和aiohttp库来编写高效的网络请求代码。我们将通过一个简单的示例来展示如何利用这些工具来并发地处理多个网络请求,从而提高程序的整体性能。准备好让你的Python代码飞起来吧!
82 2
|
1月前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
114 6
|
25天前
|
机器学习/深度学习 人工智能 算法
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
宠物识别系统,本系统使用Python作为主要开发语言,基于TensorFlow搭建卷积神经网络算法,并收集了37种常见的猫狗宠物种类数据集【'阿比西尼亚猫(Abyssinian)', '孟加拉猫(Bengal)', '暹罗猫(Birman)', '孟买猫(Bombay)', '英国短毛猫(British Shorthair)', '埃及猫(Egyptian Mau)', '缅因猫(Maine Coon)', '波斯猫(Persian)', '布偶猫(Ragdoll)', '俄罗斯蓝猫(Russian Blue)', '暹罗猫(Siamese)', '斯芬克斯猫(Sphynx)', '美国斗牛犬
130 29
【宠物识别系统】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+图像识别
|
25天前
|
机器学习/深度学习 人工智能 算法
深度学习入门:用Python构建你的第一个神经网络
在人工智能的海洋中,深度学习是那艘能够带你远航的船。本文将作为你的航标,引导你搭建第一个神经网络模型,让你领略深度学习的魅力。通过简单直观的语言和实例,我们将一起探索隐藏在数据背后的模式,体验从零开始创造智能系统的快感。准备好了吗?让我们启航吧!
62 3
|
1月前
|
网络安全 Python
Python网络编程小示例:生成CIDR表示的IP地址范围
本文介绍了如何使用Python生成CIDR表示的IP地址范围,通过解析CIDR字符串,将其转换为二进制形式,应用子网掩码,最终生成该CIDR块内所有可用的IP地址列表。示例代码利用了Python的`ipaddress`模块,展示了从指定CIDR表达式中提取所有IP地址的过程。
46 6
|
1月前
|
机器学习/深度学习 自然语言处理 语音技术
Python在深度学习领域的应用,重点讲解了神经网络的基础概念、基本结构、训练过程及优化技巧
本文介绍了Python在深度学习领域的应用,重点讲解了神经网络的基础概念、基本结构、训练过程及优化技巧,并通过TensorFlow和PyTorch等库展示了实现神经网络的具体示例,涵盖图像识别、语音识别等多个应用场景。
60 8
|
1月前
|
数据采集 XML 存储
构建高效的Python网络爬虫:从入门到实践
本文旨在通过深入浅出的方式,引导读者从零开始构建一个高效的Python网络爬虫。我们将探索爬虫的基本原理、核心组件以及如何利用Python的强大库进行数据抓取和处理。文章不仅提供理论指导,还结合实战案例,让读者能够快速掌握爬虫技术,并应用于实际项目中。无论你是编程新手还是有一定基础的开发者,都能在这篇文章中找到有价值的内容。
|
1月前
|
机器学习/深度学习 人工智能 算法
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
垃圾识别分类系统。本系统采用Python作为主要编程语言,通过收集了5种常见的垃圾数据集('塑料', '玻璃', '纸张', '纸板', '金属'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对图像数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。然后使用Django搭建Web网页端可视化操作界面,实现用户在网页端上传一张垃圾图片识别其名称。
87 0
基于Python深度学习的【垃圾识别系统】实现~TensorFlow+人工智能+算法网络
|
1月前
|
机器学习/深度学习 TensorFlow 算法框架/工具
利用Python和TensorFlow构建简单神经网络进行图像分类
利用Python和TensorFlow构建简单神经网络进行图像分类
64 3