首页 > 编程语言 >网络编程(完结)

网络编程(完结)

时间:2022-11-17 22:25:12浏览次数:34  
标签:socket 编程 程序 网络 len dict 完结 data CPU

黏包现象

什么是黏包

1.服务端连续执行三次recv(字节数需要大些)

import socket


server = socket.socket()
server.bind(('127.0.0.1', 8081))
server.listen(5)

sock, addr = server.accept()
data1 = sock.recv(1024)
print(data1)
data2 = sock.recv(1024)
print(data2)
data3 = sock.recv(1024)
print(data3)

sock.close()
server.close()

2.客户端连续执行三次send

import socket


client = socket.socket()
client.connect(('127.0.0.1', 8081))

client.send(b'hello kevin')
client.send(b'jason say hei')
client.send(b'jerry say goodbye')

问题服务端一次性接收到了客户端三次的消息 该现象称为"黏包现象"

image

黏包现象产生的原因

  1. 不知道每次的数据到底多大

  2. TCP也称为流式协议:数据像水流一样绵绵不绝没有间隔(TCP会针对数据量较小且发送间隔较短的多条数据一次性合并打包发送)

    在知道了产生的原因后我们可以想到避免黏包现象的核心思路\关键点在于如何明确即将接收的数据具体有多大

    ps:如何将长度变化的数据全部制作成固定长度的数据

struct模块

在处理黏包现象之前需要学习一个新模块:struct模块

该模块可以把一个类型,如数字,转成固定长度的bytes(当然了,有长度限制)

image

pack操作

import struct

info = b'hello big baby'
print(len(info))  # 数据真实的长度(bytes)  14
res = struct.pack('i', len(info))  # 将数据打包成固定的长度 i是固定的打包模式
print(len(res))  # 打包之后长度为(bytes)   4           报头

real_len = struct.unpack('i', res)
print(real_len)  # (14,)             根据固定长度的报头 解析出真实数据的长度


desc = b'hello my baby I will take you to play big ball'
print(len(desc))  # 数据真实的长度(bytes)  46
res1 = struct.pack('i', len(desc))
print(len(res1))  # 打包之后长度为(bytes)  4           报头

real_len1 = struct.unpack('i', res1)
print(real_len1)  # (46,)              根据固定长度的报头 解析出真实数据的长度

"""
注意:输出中的“b”代表二进制
"""

这里我们发现struct模块可以把对应的数据类型打包成固定的二进制长度然后还可以解压回去

解决黏包问题初级版本

image

解决过程中遇到的问题

image

解决黏包问题终极方案

image

import struct

data_dict = {
    'file_name': 'xxx老师教学.avi',
    'file_size': 123132131232342342423423423423432423432,
    'file_info': '内容很精彩 千万不要错过',
    'file_desc': '一代神作 私人珍藏'
}
import json
data_json = json.dumps(data_dict)
print(len(data_json.encode('utf8')))  # 真实字典的长度  228
res = struct.pack('i', len(data_json.encode('utf8')))
print(len(res))

黏包代码实操

服务端代码

import socket
import struct
import json


server = socket.socket()
server.bind(('127.0.0.1', 8081))
server.listen(5)

sock, addr = server.accept()
# 1.接收固定长度的字典报头
data_dict_head = sock.recv(4)
# 2.根据报头解析出字典数据的长度
data_dict_len = struct.unpack('i', data_dict_head)[0]
# 3.接收字典数据
data_dict_bytes = sock.recv(data_dict_len)
data_dict = json.loads(data_dict_bytes)  # 自动解码再反序列化
# 4.获取真实数据的各项信息
# total_size = data_dict.get('file_size')
# with open(data_dict.get('file_name'), 'wb') as f:
#     f.write(sock.recv(total_size))
'''接收真实数据的时候 如果数据量非常大 recv括号内直接填写该数据量 不太合适 我们可以每次接收一点点 反正知道总长度'''
# total_size = data_dict.get('file_size')
# recv_size = 0
# with open(data_dict.get('file_name'), 'wb') as f:
#     while recv_size < total_size:
#         data = sock.recv(1024)
#         f.write(data)
#         recv_size += len(data)
#         print(recv_size)

客户端

import socket
import os
import struct
import json

client = socket.socket()
client.connect(('127.0.0.1', 8081))

'''任何文件都是下列思路 图片 视频 文本 ...'''
# 1.获取真实数据大小
file_size = os.path.getsize(r'/Users/jiboyuan/PycharmProjects/day36/xx老师合集.txt')
# 2.制作真实数据的字典数据
data_dict = {
    'file_name': '有你好看.txt',
    'file_size': file_size,
    'file_desc': '内容很长 准备好吃喝 我觉得营养快线挺好喝',
    'file_info': '这是我的私人珍藏'
}
# 3.制作字典报头
data_dict_bytes = json.dumps(data_dict).encode('utf8')
data_dict_len = struct.pack('i', len(data_dict_bytes))
# 4.发送字典报头
client.send(data_dict_len)  # 报头本身也是bytes类型 我们在看的时候用len长度是4
# 5.发送字典
client.send(data_dict_bytes)
# 6.最后发送真实数据
with open(r'/Users/jiboyuan/PycharmProjects/day36/xx老师合集.txt', 'rb') as f:
    for line in f:  # 一行行发送 和直接一起发效果一样 因为TCP流式协议的特性
        client.send(line)
import time
time.sleep(10)

UDP基本代码使用

简介

 UDP 用户数据报传输协议 它位于TCP/IP协议的传输层 是一种无连接的协议 它发送的报文不能确定是否完整地到达了另外一端 UDP广泛应用于需要相互传输数据的网络应用中 如QQ使用的就是UDP协议 在网络质量不好的情况下 使用UDP协议时丢包现象十分严重 但UDP占用资源少 处理速度快 UDP依然是传输数据时常用的协议

服务器的代码

import socket
address=('127.0.0.1',10000)
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.bind(address)
while 1:
	data,addr=s.recvfrom(2048)
	if not data:
		break
	print "got data from",addr
	print data
s.close()

客户端的代码

import socket
addr=('127.0.0.1',10000)
s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
while 1:
	data=raw_input()
	if not data:
		break
	s.sendto(data,addr)
s.close()

服务端结果:

img

客户端结果:

img

并发编程理论

简介

研究网络编程其实就是在研究计算机的底层原理及发展史

在学习计算机基础知识的时候我们了解到计算机中真正干活的是CPU

操作系统发展史

1、手工操作 —— 穿孔卡片
​ 1946年第一台计算机诞生--20世纪50年代中期,计算机工作还在采用手工操作方式。此时还没有操作系统的概念
image
image
 程序员将对应于程序和数据的已穿孔的纸带(或卡片)装入输入机,然后启动输入机把程序和数据输入计算机内存,接着通过控制台开关启动程序针对数据运行;计算完毕,打印机输出计算结果;用户取走结果并卸下纸带(或卡片)后,才让下一个用户上机。

手工操作方式两个特点:

  (1)用户独占全机。不会出现因资源已被其他用户占用而等待的现象,但资源的利用率低。

  (2)CPU 等待手工操作。CPU的利用不充分。

​ 20世纪50年代后期,出现人机矛盾:手工操作的慢速度和计算机的高速度之间形成了尖锐矛盾,手工操作方式已严重损害了系统资源的利用率(使资源利用率降为百分之几,甚至更低),不能容忍。唯一的解决办法:只有摆脱人的手工操作,实现作业的自动过渡。这样就出现了成批处理。

2、批处理 —— 磁带存储
  批处理系统:加载在计算机上的一个系统软件,在它的控制下,计算机能够自动地、成批地处理一个或多个用户的作业(这作业包括程序、数据和命令)。

​ 提前使用磁带一次性录入多个程序员编写的程序 然后交给计算机执行

​ CPU工作效率有所提升 不用反复等待程序录入

1.联机批处理系统
  首先出现的是联机批处理系统,即作业的输入/输出由CPU来处理。
image
主机与输入机之间增加一个存储设备——磁带,在运行于主机上的监督程序的自动控制下,计算机可自动完成:成批地把输入机上的用户作业读入磁带,依次把磁带上的用户作业读入主机内存并执行并把计算结果向输出机输出。完成了上一批作业后,监督程序又从输入机上输入另一批作业,保存在磁带上,并按上述步骤重复处理。
监督程序不停地处理各个作业,从而实现了作业到作业的自动转接,减少了作业建立时间和手工操作时间,有效克服了人机矛盾,提高了计算机的利用率。
但是,在作业输入和结果输出时,主机的高速CPU仍处于空闲状态,等待慢速的输入/输出设备完成工作: 主机处于“忙等”状态。

2.脱机批处理系统
  为克服与缓解:高速主机与慢速外设的矛盾,提高CPU的利用率,又引入了脱机批处理系统,即输入/输出脱离主机控制。
image
image
卫星机:一台不与主机直接相连而专门用于与输入/输出设备打交道的。
  其功能是:
  (1)从输入机上读取用户作业并放到输入磁带上。
  (2)从输出磁带上读取执行结果并传给输出机。
  这样,主机不是直接与慢速的输入/输出设备打交道,而是与速度相对较快的磁带机发生关系,有效缓解了主机与设备的矛盾。主机与卫星机可并行工作,二者分工明确,可以充分发挥主机的高速计算能力。
脱机批处理系统:20世纪60年代应用十分广泛,它极大缓解了人机矛盾及主机与外设的矛盾。
  不足:每次主机内存中仅存放一道作业,每当它运行期间发出输入/输出(I/O)请求后,高速的CPU便处于等待低速的I/O完成状态,致使CPU空闲。
为改善CPU的利用率,又引入了多道程序系统。

六、多道程序设计技术
在学习并发编程的过程中 不做刻意提醒的情况下 默认一台计算机就一个CPU(只有一个干活的人)
所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行。即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬、软件资源。当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。

单道技术
​ 所有的程序排队执行 过程中不能重合

多道程序设计技术

在学习并发编程的过程中 不做刻意提醒的情况下 默认一台计算机就一个CPU(只有一个干活的人)
所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行。即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬、软件资源。当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。

单道技术
​ 所有的程序排队执行 过程中不能重合
image
在A程序计算时,I/O空闲, A程序I/O操作时,CPU空闲(B程序也是同样);必须A工作完成后,B才能进入内存中开始工作,两者是串行的,全部完成共需时间=T1+T2。

多道技术
​ 所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行。即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种硬、软件资源。当一道程序因I/O请求而暂停运行时,CPU便立即转去运行另一道程序。
image

进程理论

进程与程序的区别
	程序:一堆死代码(还没有被运行起来)
	进程:正在运行的程序(被运行起来了)
 
进程的调度算法(重要)
	1.FCFS(先来先服务)
  	对短作业不友好
	2.短作业优先调度
  	对长作业不友好
	3.时间片轮转法+多级反馈队列(目前还在用)
  	将时间均分 然后根据进程时间长短再分多个等级
    等级越靠下表示耗时越长 每次分到的时间越多 但是优先级越低

进程的并行于并发

并行

并行是指两者同时执行,比如赛跑,两个人都在不停的往前跑。(资源够用,比如三个线程,四核的CPU )

多个进程同时执行,必须要有多个CPU参与,单个CPU无法实现并行。(cpu数量要和进程数量一致或比进程数量多)

并发

并发是指资源有限的情况下,两者交替轮流使用资源,比如一段路(单核CPU资源)同时只能过一个人,A走一段后,让给B,B用完继续给A ,交替使用,目的是提高效率。

使用时间片轮转法+多级反馈队列,使多个进程看上去像同时执行。单个CPU可以实现,多个CPU肯定也可以实现。

区别

并行是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器。
并发是从宏观上,在一个时间段上可以看出是同时执行的,比如一个服务器同时处理多个session。

判断下列两句话孰对孰错

我写的程序很牛逼,运行起来之后可以实现14个亿的并行量(错的,哪有程序会用到14个亿的cpu,成本太高了)

并行量必须要有对等的CPU才可以实现

我写的程序很牛逼,运行起来之后可以实现14个亿的并发量

合情合理,完全可以实现,以后我们的项目一般都会追求高并发

ps:目前国内可以说是最牛逼的并发程序>>>:12306

进程的三种状态

image

就绪(Ready)状态

当进程已分配到除CPU以外的所有必要的资源,只要获得处理机会便可立即执行,这时的进程状态称为就绪状态。

执行/运行(Running)状态

当进程已获得处理机会,其程序正在处理机上执行,此时的进程状态称为执行状态。

阻塞(Blocked)状态

正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。

标签:socket,编程,程序,网络,len,dict,完结,data,CPU
From: https://www.cnblogs.com/oiqwyig/p/16901211.html

相关文章