day35

一、socket抽象层简介

我们知道两个进程如果需要进行通讯最基本的一个前提是能够唯一标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的IP地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用IP地址+协议+端口号唯一标示网络中的一个进程。

能够唯一标示网络中的进程后,它们就可以利用Socket进行通信了,什么是Socket呢?我们经常把Socket翻译为套接字,Socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。

二、基于tcp协议的服务端和客户端

服务端套接字函数

方法用途
s.bind() 绑定(主机,端口号)到套接字
s.listen() 开始TCP监听
s.accept() 被动接受TCP客户的连接,(阻塞式)等待连接的到来

客户端套接字函数

方法用途
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常

公共用途的套接字函数

方法用途
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() 关闭套接字

面向锁的套接字方法

方法用途
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间

面向文件的套接字的函数

方法用途
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件

 

基于tcp协议的服务端

  1 # 版本一:
  2 # socket是模块名
  3 import socket
  4 # from socket import  socket
  5 
  6 #第一个socket是模块名, 第二个socket是类名
  7 # SOCK_STREAM => 基于TCP协议写的
  8 # server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
  9 
 10 # 不传就代表tcp协议
 11 server = socket.socket()
 12 
 13 # 绑定监听的地址
 14 server.bind(('127.0.0.1',8080))
 15 
 16 # listen监听, 半连接池, 强调:可不是同时服务5个
 17 server.listen(5)
 18 
 19 # 接收消息
 20 
 21 print("正在接收客户端消息:")
 22 # sock 当前连接对象  addr 客户端的地址 ip+port
 23 print(server.accept())
 24 sock, addr = server.accept()
 25 print(sock)
 26 print(addr)
 27 
 28 # 1024 bytes
 29 data = sock.recv(1024)
 30 print(data)
 31 
 32 sock.send(data.upper())
 33 
 34 sock.close()
 35 
 36 server.close()
 37 
 38 # 版本二:加入链接循环
 39 # socket是模块名
 40 import socket
 41 # from socket import  socket
 42 
 43 #第一个socket是模块名, 第二个socket是类名
 44 # SOCK_STREAM => 基于TCP协议写的
 45 # server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
 46 
 47 # 不传就代表tcp协议
 48 server = socket.socket()
 49 
 50 # 绑定监听的地址
 51 server.bind(('127.0.0.1',8080))
 52 
 53 # listen监听, 半连接池, 强调:可不是同时服务5个
 54 server.listen(5)
 55 
 56 # 接收消息
 57 
 58 print("正在接收客户端消息:")
 59 while True:
 60     # sock 当前连接对象  addr 客户端的地址 ip+port
 61     print(server.accept())
 62     sock, addr = server.accept()
 63     print(sock)
 64     print(addr)
 65 
 66     # 1024 bytes
 67     data = sock.recv(1024)
 68     print(data)
 69 
 70     sock.send(data.upper())
 71 
 72     sock.close()
 73 
 74 server.close()
 75 
 76 # 版本三:在版本二的基础上加入通信循环
 77 # socket是模块名
 78 import socket
 79 
 80 # from socket import  socket
 81 
 82 # 第一个socket是模块名, 第二个socket是类名
 83 # SOCK_STREAM => 基于TCP协议写的
 84 # server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
 85 
 86 # 不传就代表tcp协议
 87 server = socket.socket()
 88 
 89 # 绑定监听的地址
 90 server.bind(('127.0.0.1', 8081))
 91 
 92 # listen监听, 半连接池, 强调:可不是同时服务5个
 93 server.listen(5)
 94 
 95 # 接收消息
 96 
 97 print("正在接收客户端消息:")
 98 while True:
 99     # sock 当前连接对象  addr 客户端的地址 ip+port
100     sock, addr = server.accept()
101     print(sock)
102     print(addr)
103 
104     # 1024 bytes
105     while True:
106         # 客户端非正常断开,需要捕捉异常
107         try:
108             data = sock.recv(1024)
109             if len(data) == 0:  # 当客户端主动断开时,接收的数据为空
110                 break
111             print(data)
112 
113             sock.send(data.upper())
114         except Exception as e:
115             print(e)
116             break
117 
118     sock.close()
119 
120 server.close()

 

 

基于tcp协议的客户端

 1 # 版本一:
 2 import socket
 3 
 4 client = socket.socket()
 5 
 6 client.connect(('127.0.0.1', 8080))
 7 
 8 client.send(b'sb')
 9 
10 # 接收服务端返回的结果
11 data = client.recv(1024)
12 print(data)
13 
14 client.close()
15 
16 # 版本二:加入链接
17 import socket
18 
19 client = socket.socket()
20 
21 client.connect(('127.0.0.1', 8080))
22 
23 client.send(b'sb')
24 
25 # 接收服务端返回的结果
26 data = client.recv(1024)
27 print(data)
28 
29 client.close()
30 
31 # 版本三:在版本二的基础上加入通信循环
32 import socket
33 
34 client = socket.socket()
35 
36 client.connect(('127.0.0.1', 8081))
37 
38 while True:
39 
40     input_data = input('请输入要传输的数据:(q to quit)').strip()
41 
42     if not input_data:continue
43     if input_data =='q':
44         break
45     client.send(input_data.encode('utf-8'))
46 
47     # 接收服务端返回的结果
48     data = client.recv(1024)
49     print(data)
50 
51 client.close()

三、基于udp协议的客户端和服务端

# 基于udp协议的服务端
import  socket

# SOCK_DGRAM =》  udp服务端
# SOCK_STREAM =》 tcp服务端
server = socket.socket(type=socket.SOCK_DGRAM)

server.bind(('127.0.0.1', 8080))

while True:
# client_addr: 客户端地址
    data, client_addr = server.recvfrom(1024)

    print(data)
    print(client_addr)

    server.sendto(data.upper(), client_addr)

server.close()

# 基于udp协议的客户端
import socket

client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 数据报协议-》UDP

while True:
    msg = input('>>: ').strip()  # msg=''
    client.sendto(msg.encode('utf-8'), ('127.0.0.1', 8080))

    # 接收服务端返回的数据
    data, server_addr = client.recvfrom(1024)
    print(data)

client.close()

 

四、常用端口

FTP:21,20:TCP

TFTP:69:UDP

TELNET:23:TCP

SMTP:25:TCP

DNS:53:UDP

HTTP:80:TCP

HTTPS:443:TCP

SSH:22:TCP

MYSQL:3306:TCP

五、进程的概念

操作系统背景知识

顾名思义,进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。

进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展开的。

所以想要真正了解进程,必须事先了解操作系统,点击进入

PS:即使可以利用的cpu只有一个(早期的计算机确实如此),也能保证支持(伪)并发的能力。将一个单独的cpu变成多个虚拟的cpu(多道技术:时间多路复用和空间多路复用+硬件上支持隔离),没有进程的抽象,现代计算机将不复存在。

必备的理论基础

  1. 操作系统的作用:

    1. 隐藏丑陋复杂的硬件接口,提供良好的抽象接口
    2. 管理、调度进程,并且将多个进程对硬件的竞争变得有序
  2. 多道技术:

    1. 产生背景:针对单核,实现并发

    ps:现在的主机一般是多核,那么每个核都会利用多道技术。有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个cpu中的任意一个,具体由操作系统调度算法决定。

    1. 空间上的复用:如内存中同时有多道程序
    2. 时间上的复用:复用一个cpu的时间片

    强调:遇到io切换,占用cpu时间过长也切换,核心在于切之前将进程的状态保存下来,这样才能保证下次切换回来时,能基于上次切走的位置继续运行。

什么是进程

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。

广义定义:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

进程的概念

  1. 进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
  2. 进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。

进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。

操作系统引入进程的概念的原因

从理论角度看,是对正在运行的程序过程的抽象;

从实现角度看,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。

进程的特征

  • 动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
  • 并发性:任何进程都可以同其他进程一起并发执行
  • 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
  • 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
  • 结构特征:进程由程序、数据和进程控制块三部分组成。

多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。

进程与程序中的区别

程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。

程序可以作为一种软件资料长期存在,而进程是有一定生命期的。

程序是永久的,进程是暂时的。

注意:同一个程序执行两次,就会在操作系统中出现两个进程,所以我们可以同时运行一个软件,分别做不同的事情也不会混乱。

posted @ 2021-07-20 15:39  Gnomeshghy  阅读(37)  评论(0)    收藏  举报