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

网络编程之Tcp,udp

1.TCP2.补充异常处理3.UDP一TCP.1.socket基础版本通讯服务端:1importsocket23serversocket.socket()#生成一个对

1.TCP

2.补充异常处理

3.UDP

一TCP.
1.socket基础版本通讯

服务端:

1 import socket
2
3 server = socket.socket()# 生成一个对象
4 server.bind(('127.0.0.1',8080))# 绑定ip和端口
5 server.listen(5)# 连接池
6
7 conn,addr = server.accept()# 等待别人 一个是ip 一个是地址 阻塞
8 data = conn.recv(1024) # 听别人说话 阻塞
9 print(data)
10 conn.send(b'hello boby')# 给对方回信息
11
12 conn.close()# 断开链接
13 server.close()# 结束掉进程

View Code

客户端:

1 import socket
2
3
4 client = socket.socket()# 生成一个对象
5
6 client.connect(('127.0.0.1',8080))# 发送你的ip和端口号
7
8 client.send(b'hello word')# 对别人说话
9 data = client.recv(1024) # 听别人说话
10 print(data)
11
12 client.close()# 断开链接

View Code

 

2 升级版实现多条通讯

服务端:

1 import socket
2
3 server = socket.socket() # 创建一个对象
4 server.bind(('127.0.0.1',8989)) # 绑定 ip 和端口
5 server.listen(5)# 最大连接数
6
7 while True:
8 conn,addr = server.accept() # 等待 别人链接进来 ip和端口 # 等到别人来 conn就类似于是双向通道
9 print(conn)
10 print(addr)## ('127.0.0.1', 51323) 客户端的地址
11 while True:
12 try:
13 data = conn.recv(1024)# 接收数据
14 # 判断接收的数据为不为空
15 if not data:break## b'' 针对mac与linux 客户端异常退出之后 服务端不会报错 只会一直收b''
16 conn.send(data.upper())
17 except ConnectionResetError as e:
18 print(e)
19 break
20 conn.close()

View Code

客户端:

1 import socket
2
3 client = socket.socket() # 创建一个对象
4 client.connect(('127.0.0.1',8989))# 写入要链接的ip 和端口号
5
6 while True:
7 msg = input('请输入:>>>').encode('utf-8')# 发送数据
8 # 判断数据是否为空
9 if not msg:continue
10 client.send(msg)
11 # 接收数据
12 data = client.recv(1024)
13 print(data)

View Code

 

tcp的沾包问题

客户端:

import time
import socketclient = socket.socket()
client.connect((
'127.0.0.1',8080))client.send(b'hello')
# time.sleep(5)
client.send(b'word')

服务端:

import socketserver = socket.socket()
server.bind((
'127.0.0.1',8080))
server.listen(
5)
conn,addr
= server.accept()data = conn.recv(5)
print(data)
data
= conn.recv(5)
print(data)'''
可以规定接收的数据长度,但是你不知道对方每次要发多少数据,这个接收数据的1024不能随便改,所以说要想其他的方法
解决方案就是你要提前告知收方数据的长度
'''

 

那么沾包是如何产生的:

TCP流式协议, 数据之间没有分界, 就像水 一杯水和一杯牛奶倒在一起了!UDP 用户数据报协议 粘包 仅发生在TCP协议中 1. 发送端 发送的数据量小 并且间隔短 会粘
2. 接收端 一次性读取了两次数据的内容 会粘
3. 接收端 没有接收完整 剩余的内容 和下次发送的粘在一起无论是那种情况,其根本原因在于 接收端不知道数据到底有多少 解决方案就是 提前告知接收方 数据的长度

那么如何解决沾包:

.TCP粘包问题
struct模块 对数据进行打包处理 固定长度
pack
unpack

服务端
1.生成一个字典
2.制作该字典的报头
json序列化
编码 统计长度
3.发送字典的报头
4.发送字典
5.最后发真实数据

客户端
1.先接受固定长度的4个字节字典报头
2.解析获取字典数据的长度
unpack(...)[0]
3.接受字典数据
解码 反序列化
4.接受真实数据

ps:为什么要多加一个字典
1.打包的数据大小有限
2.可以携带更多的信息

 

代码实现解决沾包问题:
客户端:

1 import socket
2 import struct
3 import json
4
5 client = socket.socket()
6 client.connect(('127.0.0.1',8080))
7
8 while True:
9 msg = input('msg:>>>').encode('utf-8')
10 if not msg:continue
11 client.send(msg)
12 # 接收字典报头
13 header = client.recv(4)
14 # 解析报头,拿到真实的数据长度
15 header_dict = struct.unpack('i',header)[0]
16 # 接收字典数据
17 dict_bytes = client.recv(header_dict)
18 json_dict = json.loads(dict_bytes.decode('utf-8'))
19 # 从字典中获取信息
20 print(json_dict)
21 recv_size = 0
22 real_data = b''
23 # 循环接收字典中的信息
24 while recv_size 'file_size'):
25 data = client.recv(1024)
26 recv_size +=len(data)
27 real_data +=data
28 print(data.decode('gbk'))
29 print(recv_size)

View Code

服务端:

1 import socket
2 import struct
3 import json
4 import subprocess
5
6 server = socket.socket()
7 server.bind(('127.0.0.1',8080))
8 server.listen(5)
9
10 while True:
11 conn,addr = server.accept()
12 while True:
13 try:
14 cmd = conn.recv(1024)
15 if not cmd:break
16 cmd = cmd.decode('utf-8')
17 obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
18 res = obj.stdout.read()+obj.stderr.read()
19 # 定义一个字典
20 d = {'name':'zy','file_size':len(res)}
21 json_d = json.dumps(d)
22 #1.制作字典报头
23 header = struct.pack('i',len(json_d))
24 #2. 发送字典报头
25 conn.send(header)
26 #3.发送字典
27 conn.send(json_d.encode('utf-8'))
28 #4.发送正式数据
29 conn.send(res)
30 except ConnectionResetError as e:
31 print(e)
32 break
33 conn.close()

View Code

补充:

解决沾包问题需要用到的struct模块:

1 import struct
2 #
3 # res = 'dgbdushfgcbdsjhgbcshjdgcbidjhgvKADJFCNalskCNkfjcnLJCHSDNCKLSD'
4 # print('最开始的',len(res))
5 #
6 # res1 = struct.pack('i',len(res))
7 # print('打包好的',len(res1))
8 #
9 # res2 = struct.unpack('i',res1)[0] # 如果不加索引解包后的结果就是解包后的 (61,),索引拿到的是0号位
10 # print('解包后的',res2)
11
12
13
14 '''
15 当原始数据特别大的时候 i模式打包不了 需要更换模式?
16 如果遇到数据量特别大的情况 该如何解决?
17 可以定义一个字典
18 '''
19 d = {
20 'name':'zy',
21 'file_size':'123473985961732617417324627346723641746723462374613274164',
22 'info':'你好',
23 }
24
25 import json
26 json_d = json.dumps(d)
27 print(len(json_d))
28
29 res1 = struct.pack('i',len(json_d))
30 print(len(res1))
31
32 res2 = struct.unpack('i',res1)[0]
33 print('解包后的数据',res2)

View Code

 

补充:复习subprocess模块

1 import subprocess
2
3 while True:
4 cmd = input('cmg:>>>')
5 if cmd == 'q':break
6 if not cmd:continue
7 obj = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
8 print(obj.stdout.read().decode('gbk'))# 正确命令返回的结果
9 print(obj.stderr.read().decode('gbk'))# 错误的命令返回的结果
10
11 #注意:subprocess获取到的数据,拿完就没有了,不能重复的拿

View Code

 

练习:大文件上传:

客户端:

1 mport struct
2 import json
3 import socket
4 import os
5
6 client = socket.socket()
7 client.connect(('127.0.0.1',8080))
8
9 while True:
10 # 获取文件路径
11 MOVIE_DIR = r'H:\python视频\python10期\day29\视频'
12 # 显示文件里的电影
13 movie_list = os.listdir(MOVIE_DIR)
14 # 循环打印电影
15 for i,movie in enumerate(movie_list,1):
16 print(i,movie)
17 # 选取电影
18 choice = input('请选择电影:>>>').strip()
19 if choice.isdigit():
20 choice = int(choice)-1
21 # 判断是否在索引范围内
22 if choice in range(0,len(movie_list)):
23 # 获取要上传电影的文件路径
24 path = movie_list[choice]
25 # 获取要上传电影的绝对路径,拼接
26 file_path = os.path.join(MOVIE_DIR,path)
27 # 获取文件的大小
28 file_size = os.path.getsize(file_path)
29 # 定义一个字典
30 d = {
31 'file_name':'qwer.mp4',
32 'file_size':file_size,
33 }
34 # 序列化字典
35 json_d = json.dumps(d)
36 json_bytes = json_d.encode('utf-8')
37 # 制作字典报头
38 header = struct.pack('i',len(json_bytes))
39 # 发送字典报头
40 client.send(header)
41 # 发送字典数据
42 client.send(json_bytes)
43 # 循环发送文件数据
44 with open(file_path,'rb') as f:
45 for line in f:
46 client.send(line)
47 else:
48 print('序号不在索引范围内')
49 else:
50 print('请输入数字')

View Code

服务端:

1 import socket
2 import struct
3 import json
4
5
6 server = socket.socket()
7 server.bind(('127.0.0.1',8080))
8 server.listen(5)
9
10 while True:
11 conn,addr = server.accept()
12 while True:
13 try:
14 # 先接收报头
15 header = conn.recv(4)
16 # 解析字典报头
17 header_len =struct.unpack('i',header)[0]
18 # 接收字典数据
19 json_bytes = conn.recv(header_len)
20 json_dict = json.loads(json_bytes.decode('utf-8'))
21 # 获取字典长度
22 len_size = json_dict.get('file_size')
23 # 循环接收文件数据
24 recv_size = 0
25 with open(json_dict.get('file_name'),'wb') as f:
26 while recv_size < len_size:
27 data &#61; conn.recv(1024)
28 f.write(data)
29 recv_size&#43;&#61;len(data)
30 print(&#39;上传成功&#39;)
31 print(recv_size)
32 except ConnectionResetError as e:
33 print(e)
34 break
35 conn.close()

View Code

 

二.异常处理

什么是异常处理&#xff1a;

  程序在运行过程中出现了不可预知的错误&#xff0c;并且该程序没有对应的处理机制’&#xff0c;

  那么就会以异常的形式表示出来&#xff0c;造成的影响就是整个程序无法在正常运行了&#xff0c;

  那么我们一般不建议使用异常处理&#xff0c;一般的异常都是可以通过修改代码可以防止

  出现异常的&#xff0c;只有那么你知道会报错&#xff0c;而不能解决的&#xff0c;

  举例&#xff1a;比如说你和别人在打电话&#xff0c;那么可能会出现一些意外&#xff0c;可能手机关机了&#xff0c;或者没信号了

  所以说在无法解决的时候在使用异常处理

 

异常的结构&#xff1a;

  1.异常的类型:NAMEERROR

  2.异常的信息:name &#39;fdsdfsdf&#39; is not defined

  3.异常的位置:Traceback (most recent call last):
  File "D:/python脱产10期视频/day29/01 异常处理.py", line 1, in
  fdsdfsdf

异常的种类&#xff1a;

  分为俩大类&#xff1a;

    1.语法上的错误&#xff1a;

      是你程序启动立刻就能解决的&#xff0c;这种错误也是不能被容忍的&#xff0c;

      语法上的错误&#xff0c;发现之后应该立即解决

    2.逻辑上的错误&#xff1a;

      这种错误是可以被容忍的&#xff0c;因为一眼看不出来&#xff0c;

      针对逻辑上的错误&#xff0c;可以采用异常处理机制进行捕获

    

    常见的错误类型&#xff1a;

      NAMERROR 名字错误

      SyntaxError 语法错误
      eyError 键不存在
      ValueError 值错误
      IndexError 索引错误

  如何避免&#xff1a;

    异常处理&#xff1a;

      在你认为可能会出现的bug的代码上方try一下&#xff1a;注意try内部的代码块越少越好

      try:

        可能出现的错误

      except 出错的类型 as e: 将报错信息赋值给变量

        出错之后的处理机制

 

三.UDP协议

udp协议简介

用户数据报协议,是OSI模型中属于传输层的协议

提供,不可靠的,不要求顺序的,数据量小的,速度快的传输服务

不可靠:

发送完成后不需要确认信息 并且立即删除缓存中的数据

不要求顺序:

当一个数据较大时 会分为多个数据报来传输,对方无法获知数据的顺序,以及是否完整

数据量较小的:

数据越大丢包的可能性越高 ,建议的数据量不要超过1472

速度快:

相对于TCP而言快很多 不需要确认信息 ,也不需要建立链接

 

udp协议的通讯流程&#xff1a;

如果TCP比喻为手机打电话的过程 那么UDP可以看做是对讲机

1.买机器 创建UDP的socket

2.固定频道 bind一个ip和端口

3.收发数据 recvfrom sendto

 

接收

1.买机器 创建UDP的socket

2.收发数据 recvfrom sendto

注意 不能先收 要收数据 必须明确端口号 没有端口号是不可能使用网络服务的

 

 

TCP 与 UDP 的其他区别

1.没有连接

2.不会粘包 每次发送都是一个独立的数据包

 

TCP 对数据完整性要求较高 : 在线支付 ,文字信息

UDP: 对数据不要求完整性 但是要快 : 视频 语音 游戏

 

 

udp协议的基本使用&#xff1a;

服务端&#xff1a;

1 import socket
2
3 server &#61; socket.socket(type&#61;socket.SOCK_DGRAM)# UDP协议
4 server.bind((&#39;127.0.0.1&#39;,8080))
5 &#39;&#39;&#39;
6 UDP不需要设置半链接池&#xff0c;它也没有半连接池的概念
7 因为没有双向通道&#xff0c;不需要accept 直接就是通信循环
8 &#39;&#39;&#39;
9 while True:
10 data,addr &#61; server.recvfrom(1024)
11 print(&#39;数据&#39;,data)# 客户端发来的信息
12 print(&#39;地址&#39;,addr)# 客户端发来的地址
13 server.sendto(data.upper(),addr)
14 break

View Code

客户端&#xff1a;

1 import socket
2
3 client &#61; socket.socket(type&#61;socket.SOCK_DGRAM)
4 #不需要建立链接&#xff0c;直接进入通信循环
5 server_address &#61; (&#39;127.0.0.1&#39;,8080)
6
7 while True:
8 client.sendto(b&#39;hello&#39;,server_address)
9 data,addr &#61; client.recvfrom(1024)
10 print(&#39;服务端发来的数据&#39;,data)
11 print(&#39;服务端发来的地址&#39;,addr)
12 break

View Code

 

udp通讯是不会沾包的&#xff1a;

服务端&#xff1a;

1 import socket
2
3 server &#61; socket.socket(type&#61;socket.SOCK_DGRAM)
4 server.bind((&#39;127.0.0.1&#39;,8080))
5
6 data,addr &#61; server.recvfrom(1024)
7 print(data)
8 data,addr1 &#61; server.recvfrom(1024)
9 print(data)
10 data,addr2 &#61; server.recvfrom(1024)
11 print(data)

View Code

客户端&#xff1a;

1 import socket
2
3
4 client &#61; socket.socket(type&#61;socket.SOCK_DGRAM)
5 server_address &#61; (&#39;127.0.0.1&#39;,8080)
6
7 client.sendto(b&#39;hello&#39;,server_address)
8 client.sendto(b&#39;hello&#39;,server_address)
9 client.sendto(b&#39;hello&#39;,server_address)

View Code

 

小练习&#xff1a;udp实现简易版本的qq

服务端&#xff1a;

1 import socket
2
3 server &#61; socket.socket(type&#61;socket.SOCK_DGRAM)
4 server.bind((&#39;127.0.0.1&#39;,8080))
5
6
7 while True:
8 data,addr &#61; server.recvfrom(1024)
9 print(data.decode(&#39;utf-8&#39;))
10 msg &#61; input(&#39;msg:>>>&#39;).strip()
11 server.sendto(msg.encode(&#39;utf-8&#39;),addr)

View Code

客户端1&#xff1a;

1 import socket
2
3 client &#61; socket.socket(type&#61;socket.SOCK_DGRAM)
4 server_address &#61; (&#39;127.0.0.1&#39;,8080)
5
6 while True:
7 msg &#61; input(&#39;msg:>>>&#39;).strip()
8 msg &#61; &#39;来自客户端1的信息:%s&#39;%msg
9 client.sendto(msg.encode(&#39;utf-8&#39;),server_address)
10 data,server_addr &#61; client.recvfrom(1024)
11 print(data.decode(&#39;utf-8&#39;))

View Code

客户端2&#xff1a;

1 import socket
2
3 client &#61; socket.socket(type&#61;socket.SOCK_DGRAM)
4 server_address &#61; (&#39;127.0.0.1&#39;,8080)
5
6 while True:
7 msg &#61; input(&#39;msg:>>>&#39;).strip()
8 msg &#61; &#39;来自客户端2的信息:%s&#39;%msg
9 client.sendto(msg.encode(&#39;utf-8&#39;),server_address)
10 data,server_addr &#61; client.recvfrom(1024)
11 print(data.decode(&#39;utf-8&#39;))

View Code

客户端3&#xff1a;

1 import socket
2
3 client &#61; socket.socket(type&#61;socket.SOCK_DGRAM)
4 server_address &#61; (&#39;127.0.0.1&#39;,8080)
5
6 while True:
7 msg &#61; input(&#39;msg:>>>&#39;).strip()
8 msg &#61; &#39;来自客户端3的信息:%s&#39;%msg
9 client.sendto(msg.encode(&#39;utf-8&#39;),server_address)
10 data,server_addr &#61; client.recvfrom(1024)
11 print(data.decode(&#39;utf-8&#39;))

View Code

 


转载于:https://www.cnblogs.com/zahngyu/p/11324021.html


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了logistic回归(线性和非线性)相关的知识,包括线性logistic回归的代码和数据集的分布情况。希望对你有一定的参考价值。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 开发笔记:计网局域网:NAT 是如何工作的?
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了计网-局域网:NAT是如何工作的?相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
  • 移动端常用单位——rem的使用方法和注意事项
    本文介绍了移动端常用的单位rem的使用方法和注意事项,包括px、%、em、vw、vh等其他常用单位的比较。同时还介绍了如何通过JS获取视口宽度并动态调整rem的值,以适应不同设备的屏幕大小。此外,还提到了rem目前在移动端的主流地位。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 本文介绍了如何使用JSONObiect和Gson相关方法实现json数据与kotlin对象的相互转换。首先解释了JSON的概念和数据格式,然后详细介绍了相关API,包括JSONObject和Gson的使用方法。接着讲解了如何将json格式的字符串转换为kotlin对象或List,以及如何将kotlin对象转换为json字符串。最后提到了使用Map封装json对象的特殊情况。文章还对JSON和XML进行了比较,指出了JSON的优势和缺点。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
author-avatar
蓝色流星魂
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有