Scoket抽象层

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

能够唯一标示网络中的进程后,它们就可以利用Socket进行通信了,什么是Socket呢?我们经常把Socket翻译为套接字,Socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。
网络编程 套接字_unix
Socket起源于UNIX,在Unix一切皆文件哲学的思想下,Socket是一种”打开—读/写—关闭”模式的实现,服务器和客户端各自维护一个”文件”,在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。

基于TCP的socket服务端和客户端

服务端

server:服务端是为客户端服务的,服务的内容诸如向客户端提供资源,数据的逻辑处理,保存用户数据等

客户端

而客户端根据软件架构的不同:分为C/S和B/S

C表示的是软件客户端,电脑上的客户端一般是C++写的

B表示的是浏览器客户端,由网页组成的

http默认端口:80,https默认端口:443

套接字发展史分类

套接字起源于 20 世纪 70 年代加利福尼亚大学伯克利分校版本的 Unix,即人们所说的 BSD Unix。 因此,有时人们也把套接字称为“伯克利套接字”或“BSD 套接字”。一开始,套接字被设计用在同 一台主机上多个应用程序之间的通讯。这也被称进程间通讯,或 IPC。套接字有两种(或者称为有两个种族),分别是基于文件型的和基于网络型的。

基于文件类型的套接字家族

套接字家族的名字:AF_UNIX

unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信

基于网络类型的套接字家族

套接字家族的名字:AF_INET

(还有AF_INET6被用于ipv6,还有一些其他的地址家族,不过,他们要么是只用于某个平台,要么就是已经被废弃,或者是很少被使用,或者是根本没有实现,所有地址家族中,AF_INET是使用最广泛的一个,python支持很多种地址家族,但是由于我们只关心网络编程,所以大部分时候我么只使用AF_INET)

套接字工作流程

网络编程 套接字_unix_02

先从服务器端说起。服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束,使用以下Python代码实现:

# 服务端
import socket

# 第一个socket是模块名 第二个是类名
# SOCK_STREAM ==>基于TCP协议写的
# server = socket.socket(family=socket.AF_INET,type=socket.SOCK_STREAM)
# 不传就代表tcp协议
server = socket.socket()
# 获取主机名
host = socket.gethostname()
port = 8972
# 绑定监听的地址
server.bind((host, port))
# listen监听,传入半连接池
server.listen(5)

# 接收消息
# sock 为当前链接对象 addr 为客户端的地址 即 ip+port
print(host,'正在准备接受')
sock, addr = server.accept()
print(sock)
print(addr)


# 1024 bytes
data = sock.recv(1024)
print(data)

sock.send(data.upper())

sock.close()

server.close()
# 客户端
import socket

client = socket.socket()

host = socket.gethostname()
port = 8972
# 链接到服务端主机
client.connect((host, port))
client.send(b'hello,word')
# 接收服务端返回结果
data = client.recv(1024)
print(data)

client.close()

UDP套接字:

# 服务端
import socket

server = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)

host = socket.gethostname()
port = 8891

server.bind((host, port))
# client_addr:客户端地址
data, client_addr = server.recvfrom(1024)
print(data)
print(client_addr)
server.sendto(data.upper(),client_addr)
server.close()
# 客户端
import socket

client = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
host = socket.gethostname()
port = 8891
client.sendto(b'hello', (host, port))
data, server_addr = client.recvfrom(1024)
print(data)
client.close()

并发编程

进程的概念:是系统进行资源分配和调度的基本单位

狭义定义:进程是正在运行的程序实例

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

线程是操作系统执行的最小单位。进程不是实际干活的人,实际干活的认是线程

先来先服务调度算法

先来先服务(FCFS)调度算法是一种最简单的调度算法,该算法既可用于作业调度,也可用于进程调度。FCFS算法比较有利于长作业(进程),而不利于短作业(进程)。由此可知,本算法适合于CPU繁忙型作业,而不利于I/O繁忙型的作业(进程)。

短作业优先调度算法

短作业(进程)优先调度算法(SJ/PF)是指对短作业或短进程优先调度的算法,该算法既可用于作业调度,也可用于进程调度。但其对长作业不利;不能保证紧迫性作业(进程)被及时处理;作业的长短只是被估算出来的。