自计算机诞生以来,计算机网络逐渐从单机模型发展成了网络互联模型
最初只是远程终端连接,终端(键盘和显示器)分布在各地然后与主机相连,用户通过终端来与远程主机进行交互,终端只能与主机通信
再到多个主机之间互联,几台固定的计算机相连在一起形成计算机网络,这种网络一般是私有的(局域网)
随着时代的发展,人们开始尝试在私有网络上搭建更大的私有网络,逐渐又发展演变为互联网,现在我们每个人几乎都能够享有互联网带来的便利
计算机网络就是把各个计算机相互连接,让网络中的计算机能够互相通信传递数据,而网络编程就是实现程序如何在两台计算机之间进行通信
既然网络编程能让两个程序进行通信,在网络中,程序是通过什么来找到另一个程序的?
套接字(socket),表示方式为点分十进制的lP地址后面写上端口号,中间用冒号或逗号隔开(IP地址:端口号)
有了套接字,不同计算机之间的程序就可以进行双向通信
一般两个程序间的通信对应的软件开发架构有两种——C/S 架构和 B/S 架构
C/S 架构
Client 与 Server
客户端与服务器端架构,这种架构是从用户层面(也可以是物理层面)来划分的
这里的客户端一般泛指客户端应用程序,程序需要先安装后,才能运行在用户的电脑上,对用户的电脑操作系统环境依赖较大
例如:QQ、微信、网盘
B/S 架构
Browser 与 Server
浏览器端与服务器端架构,这种架构也是从用户层面来划分的
浏览器,其实也是一种 Client,只是这个 Client 不需要大家去安装什么应用程序,只需在浏览器上通过 HTTP 请求 server 相关的资源(网页资源)
例如:百度、各种应用的网页版
socket
Python 提供了两个级别的网络服务模块:
-
socket
-
低级别的网络服务模块,提供了标准的 BSD Sockets API,可以访问底层操作系统 Socket 接口的全部方法
-
socketserver
-
高级别的网络服务模块,它提供了服务器中心类,可以简化网络服务器的开发
今天我们主要介绍 socket 模块
先导入 socket 模块
import socket
![](/i/l/?n=23&i=blog/2958925/202302/2958925-20230227104054383-727928342.png)
-
family:套接字家族;可以是 AF_UNIX 或者 AF_INET
-
type:套接字类型;可以根据是面向连接(TCP)的还是非连接(UDP)分为 SOCK_STREAM 或 SOCK_DGRAM
-
protocol:一般不填默认为 0
server 端 socket 函数
client 端 socket 函数
公共 socket 函数
TCP 编程
如上图左边所示,server 进程首先要绑定一个端口并监听来自 client 的连接,如果某个 client 的连接过来了,server 就与 该 client 建立 socket 连接
所以 server 会打开端口(比如 80)监听,每来一个 client ,就创建该 socket 连接
考虑到会有大量的 client 与 server 进行连接,server要能够区分一个 socket 连接对应哪个 client
一个 socket 由四个元素组成:
-
server 地址(目标地址)
-
client 地址(源地址)
-
server 端口(目标端口)
-
client 端口(源端口)
除此之外,server 还需要同时响应多个 client 的请求,所以每个连接都需要一个新的进程或者新的线程来处理,否则 server 一次就只能处理一个 client 的请求了
我们来编写一个简单的 server 程序,它接受 client 连接,把 client 发过来的数据加上 hello 再返回给 client
首先创建一个基于 ipv4 和 TCP 协议的 socket 对象
然后我们绑定监听的地址和端口(可以绑定到某一块网卡的IP地址上,也可以用0.0.0.0
绑定到所有的网络地址,还可以用 127.0.0.1
绑定到本机地址)
这里我们是通过本机来实现 C/S 架构,所以绑定到 127.0.0.1 上,而且不要绑定端口号小于 1024 的端口(要有管理员权限才能绑定)
ps:端口复用
我们知道 TCP 关闭连接有一个四次挥手的过程,当 server 主动关闭连接时,会有一个TIME_WAIT(时间等待)状态,等待 2MSL(最长报文段寿命)后进入关闭状态
那么在这个 TIME_WAIT 状态下,端口还处于被别的进程绑定的状态之中,那么其他进程就会拿不到这个端口,产生报错
我们可以通过端口复用来解决这个问题
![](/i/l/?n=23&i=blog/2958925/202302/2958925-20230227104228436-1154411915.png)
![](/i/l/?n=23&i=blog/2958925/202302/2958925-20230227104230765-689471952.png)
接着开始监听端口,参数为指定等待连接的最大数量
server 程序通过一个 while 循环来接受来自 client 的连接,accept()
会等待并返回一个 client 的连接
当有 client 来连接时,就创建一个线程来处理会话
![](/i/l/?n=23&i=blog/2958925/202302/2958925-20230227104245781-701196739.png)
连接建立后,server 首先返回一条欢迎消息,然后等待 client 的数据,收到数据之后并加上 hello 再发送给 client
如果没有数据或者 client 发送了 exit 字符串就关闭连接
接下来我们编写一个 client 程序
创建一个基于 ipv4 和 TCP 协议的 socket 对象
客户端要主动发起 TCP 连接,必须知道服务器的 IP 地址和端口号
TCP 连接创建的是双向通道,双方都可以同时给对方发数据。但是谁先发谁后发,怎么协调,要根据具体的协议来决定
例如,HTTP协议规定 client 必须先发请求给 server,server 收到后才发数据给 client
接收数据时,调用 recv(max) 方法,一次最多接收指定的字节数
![](/i/l/?n=23&i=blog/2958925/202302/2958925-20230227104318262-1828882980.png)
我们将数据发送给 server,并接收 server 返回的数据
当通信完之后,发送 exit 给 server,然后调用 close() 方法关闭 Socket,这样,一次完整的网络通信就结束了
s.close()
UDP 编程
TCP 是建立可靠连接,并且通信双方都可以以流(stream)的形式发送数据,相对于 TCP ,UDP 则是面向无连接的协议
使用 UDP 协议时,不需要建立连接,只需要知道对方的 IP 地址和端口号就可以直接发送数据包
虽然用 UDP 传输数据不可靠,但它的优点是和 TCP 比,速度快,对于不要求可靠到达的数据,就可以使用 UDP 协议
首先编写一个 server 程序
创建一个 socket 对象,SOCK_DGRAM 指定使用面向流的 UDP 协议
绑定端口 8888,也可以绑定 9999
服务器绑定 UDP 端口和 TCP 端口互不冲突,也就是说,UDP 的 9999 端口与 TCP 的 9999 端口可以各自绑定
与 TCP 不同的是,UDP 不需要监听端口,而是直接接收来自 client 的数据
然后编写一个 client 程序
创建一个 socket 对象,SOCK_DGRAM 指定使用面向流的 UDP 协议
client 使用 UDP 时,首先仍然创建基于 UDP 的 Socket,然后,不需要调用 connect(),直接通过 sendto() 给 server 发数据
感谢阅读,喜欢作者就动动小手[一键三连],这是我写作最大的动力
标签:UDP,socket,Python,编程,端口,网络,server,client,连接 From: https://www.cnblogs.com/edisonfish/p/17158866.html