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

相关文章
|
26天前
|
搜索推荐 程序员 调度
精通Python异步编程:利用Asyncio与Aiohttp构建高效网络应用
【10月更文挑战第5天】随着互联网技术的快速发展,用户对于网络应用的响应速度和服务质量提出了越来越高的要求。为了构建能够处理高并发请求、提供快速响应时间的应用程序,开发者们需要掌握高效的编程技术和框架。在Python语言中,`asyncio` 和 `aiohttp` 是两个非常强大的库,它们可以帮助我们编写出既简洁又高效的异步网络应用。
107 1
|
4天前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
28 6
|
2天前
|
数据采集 存储 XML
Python实现网络爬虫自动化:从基础到实践
本文将介绍如何使用Python编写网络爬虫,从最基础的请求与解析,到自动化爬取并处理复杂数据。我们将通过实例展示如何抓取网页内容、解析数据、处理图片文件等常用爬虫任务。
|
5天前
|
数据采集 前端开发 中间件
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第26天】Python是一种强大的编程语言,在数据抓取和网络爬虫领域应用广泛。Scrapy作为高效灵活的爬虫框架,为开发者提供了强大的工具集。本文通过实战案例,详细解析Scrapy框架的应用与技巧,并附上示例代码。文章介绍了Scrapy的基本概念、创建项目、编写简单爬虫、高级特性和技巧等内容。
21 4
|
5天前
|
网络协议 物联网 API
Python网络编程:Twisted框架的异步IO处理与实战
【10月更文挑战第26天】Python 是一门功能强大且易于学习的编程语言,Twisted 框架以其事件驱动和异步IO处理能力,在网络编程领域独树一帜。本文深入探讨 Twisted 的异步IO机制,并通过实战示例展示其强大功能。示例包括创建简单HTTP服务器,展示如何高效处理大量并发连接。
20 1
|
6天前
|
数据采集 存储 机器学习/深度学习
构建高效的Python网络爬虫
【10月更文挑战第25天】本文将引导你通过Python编程语言实现一个高效网络爬虫。我们将从基础的爬虫概念出发,逐步讲解如何利用Python强大的库和框架来爬取、解析网页数据,以及存储和管理这些数据。文章旨在为初学者提供一个清晰的爬虫开发路径,同时为有经验的开发者提供一些高级技巧。
10 1
|
8天前
|
Kubernetes 网络协议 Python
Python网络编程:从Socket到Web应用
在信息时代,网络编程是软件开发的重要组成部分。Python作为多用途编程语言,提供了从Socket编程到Web应用开发的强大支持。本文将从基础的Socket编程入手,逐步深入到复杂的Web应用开发,涵盖Flask、Django等框架的应用,以及异步Web编程和微服务架构。通过本文,读者将全面了解Python在网络编程领域的应用。
10 1
|
9天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
27 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
17天前
|
消息中间件 监控 网络协议
Python中的Socket魔法:如何利用socket模块构建强大的网络通信
本文介绍了Python的`socket`模块,讲解了其基本概念、语法和使用方法。通过简单的TCP服务器和客户端示例,展示了如何创建、绑定、监听、接受连接及发送/接收数据。进一步探讨了多用户聊天室的实现,并介绍了非阻塞IO和多路复用技术以提高并发处理能力。最后,讨论了`socket`模块在现代网络编程中的应用及其与其他通信方式的关系。
|
22天前
|
机器学习/深度学习 人工智能 算法
【玉米病害识别】Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练
玉米病害识别系统,本系统使用Python作为主要开发语言,通过收集了8种常见的玉米叶部病害图片数据集('矮花叶病', '健康', '灰斑病一般', '灰斑病严重', '锈病一般', '锈病严重', '叶斑病一般', '叶斑病严重'),然后基于TensorFlow搭建卷积神经网络算法模型,通过对数据集进行多轮迭代训练,最后得到一个识别精度较高的模型文件。再使用Django搭建Web网页操作平台,实现用户上传一张玉米病害图片识别其名称。
46 0
【玉米病害识别】Python+卷积神经网络算法+人工智能+深度学习+计算机课设项目+TensorFlow+模型训练