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,如需转载请自行联系原作者

相关文章
|
2天前
|
数据采集 存储 JavaScript
构建你的第一个Python网络爬虫
【9月更文挑战第34天】在数字信息泛滥的时代,快速有效地获取和处理数据成为一项重要技能。本文将引导读者通过Python编写一个简易的网络爬虫,实现自动化地从网页上抓取数据。我们将一步步走过代码的编写过程,并探讨如何避免常见陷阱。无论你是编程新手还是想扩展你的技术工具箱,这篇文章都将为你提供有价值的指导。
35 18
|
18天前
|
机器学习/深度学习 算法 TensorFlow
动物识别系统Python+卷积神经网络算法+TensorFlow+人工智能+图像识别+计算机毕业设计项目
动物识别系统。本项目以Python作为主要编程语言,并基于TensorFlow搭建ResNet50卷积神经网络算法模型,通过收集4种常见的动物图像数据集(猫、狗、鸡、马)然后进行模型训练,得到一个识别精度较高的模型文件,然后保存为本地格式的H5格式文件。再基于Django开发Web网页端操作界面,实现用户上传一张动物图片,识别其名称。
48 1
动物识别系统Python+卷积神经网络算法+TensorFlow+人工智能+图像识别+计算机毕业设计项目
|
19天前
|
开发者 Python
Python Socket编程:不只是基础,更有进阶秘籍,让你的网络应用飞起来!
在数字时代,网络应用成为连接世界的桥梁。Python凭借简洁的语法和丰富的库支持,成为开发高效网络应用的首选。本文通过实时聊天室案例,介绍Python Socket编程的基础与进阶技巧。基础篇涵盖服务器和客户端的建立与数据交换;进阶篇则探讨多线程与异步IO优化方案,助力提升应用性能。通过本案例,你将掌握Socket编程的核心技能,推动网络应用飞得更高、更远。
32 1
|
17天前
|
机器学习/深度学习 人工智能 算法
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
植物病害识别系统。本系统使用Python作为主要编程语言,通过收集水稻常见的四种叶片病害图片('细菌性叶枯病', '稻瘟病', '褐斑病', '稻瘟条纹病毒病')作为后面模型训练用到的数据集。然后使用TensorFlow搭建卷积神经网络算法模型,并进行多轮迭代训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地模型文件。再使用Django搭建Web网页平台操作界面,实现用户上传一张测试图片识别其名称。
70 21
植物病害识别系统Python+卷积神经网络算法+图像识别+人工智能项目+深度学习项目+计算机课设项目+Django网页界面
|
17天前
|
机器学习/深度学习 人工智能 算法
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
鸟类识别系统。本系统采用Python作为主要开发语言,通过使用加利福利亚大学开源的200种鸟类图像作为数据集。使用TensorFlow搭建ResNet50卷积神经网络算法模型,然后进行模型的迭代训练,得到一个识别精度较高的模型,然后在保存为本地的H5格式文件。在使用Django开发Web网页端操作界面,实现用户上传一张鸟类图像,识别其名称。
60 12
鸟类识别系统Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+ResNet50算法模型+图像识别
|
17天前
|
机器学习/深度学习 算法 TensorFlow
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
交通标志识别系统。本系统使用Python作为主要编程语言,在交通标志图像识别功能实现中,基于TensorFlow搭建卷积神经网络算法模型,通过对收集到的58种常见的交通标志图像作为数据集,进行迭代训练最后得到一个识别精度较高的模型文件,然后保存为本地的h5格式文件。再使用Django开发Web网页端操作界面,实现用户上传一张交通标志图片,识别其名称。
44 6
交通标志识别系统Python+卷积神经网络算法+深度学习人工智能+TensorFlow模型训练+计算机课设项目+Django网页界面
|
13天前
|
机器学习/深度学习 人工智能 算法
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
文本分类识别系统。本系统使用Python作为主要开发语言,首先收集了10种中文文本数据集("体育类", "财经类", "房产类", "家居类", "教育类", "科技类", "时尚类", "时政类", "游戏类", "娱乐类"),然后基于TensorFlow搭建CNN卷积神经网络算法模型。通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型,并保存为本地的h5格式。然后使用Django开发Web网页端操作界面,实现用户上传一段文本识别其所属的类别。
24 1
【新闻文本分类识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
|
9天前
|
机器学习/深度学习 数据采集 网络安全
使用Python实现深度学习模型:智能网络安全威胁检测
使用Python实现深度学习模型:智能网络安全威胁检测
38 5
|
12天前
|
数据采集 存储 JavaScript
构建您的第一个Python网络爬虫:抓取、解析与存储数据
【9月更文挑战第24天】在数字时代,数据是新的金矿。本文将引导您使用Python编写一个简单的网络爬虫,从互联网上自动抓取信息。我们将介绍如何使用requests库获取网页内容,BeautifulSoup进行HTML解析,以及如何将数据存储到文件或数据库中。无论您是数据分析师、研究人员还是对编程感兴趣的新手,这篇文章都将为您提供一个实用的入门指南。拿起键盘,让我们开始挖掘互联网的宝藏吧!
|
13天前
|
机器学习/深度学习 人工智能 算法
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台。果蔬识别系统,本系统使用Python作为主要开发语言,通过收集了12种常见的水果和蔬菜('土豆', '圣女果', '大白菜', '大葱', '梨', '胡萝卜', '芒果', '苹果', '西红柿', '韭菜', '香蕉', '黄瓜'),然后基于TensorFlow库搭建CNN卷积神经网络算法模型,然后对数据集进行训练,最后得到一个识别精度较高的算法模型,然后将其保存为h5格式的本地文件方便后期调用。再使用Django框架搭建Web网页平台操作界面,实现用户上传一张果蔬图片识别其名称。
34 0
【果蔬识别系统】Python+卷积神经网络算法+人工智能+深度学习+计算机毕设项目+Django网页界面平台
下一篇
无影云桌面