一. 网络通信概述
- 网络: 网络是一种辅助双方或者多方可以连接在一起的工具
- 使用网络的目的:
1) 用网络能将多方连接在一起,然后进行数据传递
2) 网络编程就是让在不同的电脑上的软件能够进行数据传递,即进程间的通信
二. TCP/IP 协议
(一)基本定义
- 网络协议: 网络协议为计算机网络中进行数据交换而建立的规则、标准或约定的集合。
每一个计算机都遵守的网络协议称作是TCP/IP 协议 - TCP/IP协议(族)
互联网的众多协议中,最重要的就是TCP/IP协议。所以将互联网的协议简称为TCP/IP 协议。

(二)IP地址
- 定义: 因特网上的每台计算机和其它设备都规定了一个唯一的地址,叫做“IP地址。由于有这种唯一的地址,才保证了用户在连网的计算机上操作时,能够高效而且方便地从千千万万台计算机中选出自己所需的对象来。
- IP 地址的作用
用来在网络中标记一台电脑的一串数字,比如说192.168.1.1 在本地局域网上是唯一的 - IP地址的分类
每一个IP地址都包括两部分: 网络地址和主机地址
ipv4 : 点分十进制
ipv6: 冒分十六进制

4. 私有IP
在网络IP中,国际规定有一部分的IP是属于私有的,也就是不能在公共场合使用 范围是:
10.0.0.0 ~ 10.255.255.255
172.16.0.0 ~ 172.31.255.255
192.168.0.0 ~ 192.268.255.255
- 回环IP
IP 地址是127.0.0.1 代表本机IP ,等于localhost 就是回环IP 可以用http://27.0.0.1 可以测试本机中的web 服务器
(三)子网掩码
子网掩码是不能单独使用的,它必须结合IP地址一起使用
子网掩码的作用:
将某个IP地址划分成网络地址和 主机地址这两部分。 子网掩码的设定必须遵照一定的规则,用来判断两个 IP 是否 在同一个网络
eg: A 172.25.254.18/24
B 172.25.0.10/24
(四) 端口
- 定义:
"端口"是英文port的意译,可以认为是设备与外界通讯交流的出口。是唯一辨识进程的,便于不同程序之间的交流
因为: PID 在每次重新 开启程序的时候就会发生变化 - 分类
端口可分为虚拟端口和物理端口
其中虚拟端口指计算机内部或交换机路由器内的端口,不可见。例如计算机中的80端口、21端口、23端口等。物理端口又称为接口,是可见端口,计算机背板的RJ45网口,交换机路由器集线器等RJ45端口。电话使用RJ11插口也属于物理端口的范畴。 - 端口只能是整数,范围是0~65535

常见的端口:
ssh : 22
mysql : 3306
http : 80
https : 443
三. Socket 编程
(一) 基本概念
-
本地 进程间的通信: 队列,管道, 同步(互斥锁,条件变量等)
-
网络间的进程通信:
网络层的 “ IP地址 ” 可以唯一 标识网络中的主机,而传输层的 “ 协议+ 端口” 可以唯一标识主机中的应用程序(进程)。因此利用IP地址,协议,端口就可以识别网络的进程 -
socket 定义:
socket (简称套接字) 是进程间的的一种通信方式,能够实现不同主机间的进程间的通信,我们在网络上的各种各样 服务大多都是基于socket 来完成通信的。 -
创建socket
在 Python 中 使⽤socket 模块的函数 socket 就可以完成: socket.socket(AddressFamily, Type)
1). Address Family:
AF_INET: IPV4⽤于 Internet 进程间通信
AF_INET6: IPV6⽤于 Internet 进程间通信
2). Type:套接字类型
SOCK_STREAM: 流式套接字,主要⽤于 TCP 协议
SOCK_DGRAM: 数据报套接字,主要⽤于 UDP 协 议
(二) UDP
-
定义
UDP : 用户数据报文协议, 是一个无连接的简单的面向数据报文的运输层协议。包括⽬的端⼝号和源端⼝号信息 -
特点
1) 无连接
每一个数据报文都是一个独立的消息。包括完整的源地址或者目标地址。
由于通讯不需要连接,所以可以实现⼴播发送。
2)不可靠
UDP 不提供可靠性, 只是将应用程序给IP层的数据报发出去,但并不能保证能够到达目的地。并且发送⽅所发送的数据报并不⼀定以相同的次序到达接收⽅。
3) 传输速度快
UDP 因为在传输数据报前不用在客户端和服务器之间建立一个连接,并且没有超时重发等机制,因此传输的速度很快
4) 大小限制
UDP传输数据时有⼤⼩限 制,每个被传输的数据报必须限定在64KB之内。

-
应用场景
UDP 是面向消息的协议, 通信的时候 不需要建立联系,且不可靠
因此主要应用与多点通信和实时的数据任务
语音广播, 视频, QQ , TFTP(简单文件传输) , SMMP(简单网络管理协议)
DNS(域名解析) -
工作流程

实现代码如下:
服务端:
import socket
udpServer = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
udpServer.bind(('0.0.0.0', 10001)) # 10001 : 绑定的端口,返回的是元组
while True:
recvData, address = udpServer.recvfrom(1024) # 接收1024字节 # , 第一个是客户端发送的信息,第二个是客户端和服务端交互的地址
print("等待客户端UDP 连接")
print("客户端:", recvData.decode('utf-8'))
if recvData == b'quit':
break
b = input("请输入回复:").encode('utf-8')
if not b:
continue
udpServer.sendto(b, address) # 发送的必须是bytes类型
udpServer.close()
客户端:
import socket
udpClient = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
print("聊天开始")
while True:
a = input("请输入要说的话:").encode('utf-8')
udpClient.sendto((a),('172.25.254.46', 10001))
if a == b'quit':
break
if not a :
continue
recvData, address = udpClient.recvfrom(1024)
print("接收服务端的数据:", recvData.decode('utf-8'))
udpClient.close()
(三) TCP
- 定义
TCP :传输控制协议(Transmission Control Protocol ) 是一个面向连接的, 可靠 的,基于字节流的传输层通信协议 - 执行过程

三次握手:

SYN : 同步序列标号
ACK : 确认包
四个状态: SYN_SENT , LISTEN() , SYN_RCVD , ESTABLISHED
过程:
第一次握手: 客户端向服务器发送连接请求时,客户端回答送同步序列标号SYN 到服务器,假设SYN = x ,等待服务器确认,这时客户端地的状态是 SYN_ SENT
第二次握手: 当服务器收到客户端发送的SYN 之后,服务器 要确认客户端发过来的SYN , 在这里服务器发送确认包ACK , 这里ACK + 1 , 意思就是: “ 已经成功接收到发送的SYN 了” , 同时服务端也会向客户端发送一个SYN 打包,这时服务器的状态时SYN_RECV.
第三次握手: 客户端收到服务器发送的SYN 和ACK 包之后, 需要向服务器发送确认包ACK , “我也收到你发送的SYN 了,我也会给你发送个确认”,发送完毕后,客户端和服务端的状态就是ESTABLISH , 即TCP 连接成功
四次分手:
当客户端和服务端断开连接的时候,需要进行四次分手

断开连接的请求是由客户端发起的
第一次分手: 客户端向服务端发送一个带有FIN 标记的报文段
第二次分手: 服务端收到客户端发送的FIN , 服务端可能还有数据没有传输结束,所以服务端不会立刻向客户端发送FIN ,而是先发送一个ACK ,意思是 “ 你的请断开链接求我收到了,但我数据没有发送完,稍等”
第三次分手: 当服务端的数据传输结束后,服务端便可以断开连接,服务端会向客户端发送FIN
第四次分手: 客户端收到服务端发送的FIN之后,会向服务端发送确认ACK ,然后经过两个MSL 时长之后断开连接
实验代码如下:
服务端:
import socket
import os
# 1. 创建socket对象
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 2. 绑定地址和端口
server.bind(('172.25.46.250', 1880))
# 3. 监听
server.listen(5)
print("server服务启动")
# 4. 接收客户端的连接
clientObj, clientAddr = server.accept()
while True:
# 5. 接收客户端发送的消息
recn_data = clientObj.recv(1024).decode('utf-8')
print("接收到客户端发送的消息:", recn_data)
# 6. 给客户端发送消息
if recn_data == 'quit':
break
obj = os.popen(recn_data)
result = obj.read()
clientObj.send(result.encode('utf-8'))
# 7.关闭socket对象
clientObj.close()
server.close()
客户端:
import socket
import os
# 1. 创建socket对象
client = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 2. 连接服务端
client.connect(('172.25.46.250', 1880))
while True:
# 3. 给服务端发送消息
sendMessage = input("client >> ").encode('utf-8')
client.send(sendMessage)
if not sendMessage:
continue
# 4. 接收服务端发送的消息
recv_data = client.recv(1024).decode('utf-8')
print("接收服务端发送的消息:", recv_data)
if sendMessage == b'quit':
break
# 5. 关闭socket对象
client.close()
(四)并发服务器
1.分类
并发服务器是socket 应用编程中最常见的应用模型,
1)根据连接方式可以跟为长连接和短连接
长连接: 通过SOCCKET 连接后不管是否使用都保持连接
短连接: 双方有数据交互的时候,建立TCP 连接,数据发送完成后断开连接。
2) 根据处理方式可以分为同步方式和异步方式
同步是 客户端发送请求给服务端等待服务器返回处理结果
异步是客户端发送请求给服务端,不等待服务器返回处理结果,而直接去完成其他流程,对于处理结果客户端可以事后查询和让服务器进行主动通知

- 多进程服务器:
单进程服务器: 同一时刻只能为一个客户进行服务,不能同时为多个进行服务
多进程服务器: 同时为多个客户进行服务
多进程优点: 通过为每个客户端创建一个进程的方式,能够同时为多个客户端进行服务
多进程确点: 当客户端不是特别多的时候,这种方式可行,但是要有上千个,那么每次创建进程的过程就需要消耗较大的资源,不可取

代码实现:
服务端:
import socket
from multiprocessing import Process
def dealWithClient(clientObj, clientAddress):
while True:
# 5. 接收客户端发送的消息
recn_data = clientObj.recv(1024).decode('utf-8')
print(clientAddress[0] + str(clientAddress[1]) + ':>' + recn_data)
# 6. 给客户端发送消息
if recn_data == 'quit':
break
clientObj.close()
# 1. 创建socket对象
server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 2. 绑定地址和端口
server.bind(('172.25.46.250', 1380))
# 3. 监听
server.listen(5)
print("server服务启动")
while True:
clientObj, clientAddr = server.accept()
p = Process(target=dealWithClient, args=(clientObj, clientAddr))
p.start()
客户端1:
import socket
# 1. 创建socket对象
client = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 2. 连接服务端
client.connect(('172.25.46.250', 1380))
while True:
# 3. 给服务端发送消息
sendMessage = input("client 1>> ").encode('utf-8')
if not sendMessage:
continue
client.send(sendMessage)
# 4. 接收服务端发送的消息
if sendMessage == b'quit':
break
# 5. 关闭socket对象
client.close()
客户端2:
import socket
# 1. 创建socket对象
client = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
# 2. 连接服务端
client.connect(('172.25.46.250', 1380))
while True:
# 3. 给服务端发送消息
sendMessage = input("client 2>> ").encode('utf-8')
if not sendMessage:
continue
client.send(sendMessage)
# 4. 接收服务端发送的消息
if sendMessage == b'quit':
break
# 5. 关闭socket对象
client.close()
总结

本文介绍了网络通信的基础知识,包括TCP/IP协议、IP地址、子网掩码和端口的概念。详细阐述了Socket编程的基本原理及UDP、TCP两种主要协议的特点与应用。并通过示例代码展示了如何使用Python实现简单的并发服务器。
290

被折叠的 条评论
为什么被折叠?



