py网络_echo程序模型笔记

echo程序模型

在网络编程之中有一个经典的程序模型:ECHO程序模型,这个ECHO程序模型实际上是源于echo命令,在操作系统内部提供有一个echo命令进行内容的回显。

1
echo hello,xiaoMing
1
hello,xiaoMing

那么如果将此时的echo的概念扩大到网络环境之中,就可以理解为客户端输入一组数据发送服务端,那么服务端接收之后要对该数据进行响应,几乎原样返回,这种模型就是网络编程echo模型。像个应声虫。

本次的程序服务端对客户端发送来的数据进行一些处理,在每一条数据响应之前加有一个“【ECHO】”的前缀以表示服务端的响应,目的是进行一些请求和响应信息的区分。

测试

echo程序服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# coding : UTF-8
import socket
SERVER_HOST = "127.0.0.1"
SERVER_POST = 8080 # 服务绑定端口
def main(): # 主函数
# socket网络服务在每一次处理完成之后一定要使用close()方法进行关闭,所以可以利用with结构进行定义
with socket.socket() as server_socket: # 创建了一个服务端的Socket
server_socket.bind((SERVER_HOST,SERVER_POST)) # 绑定本机的8080端口
server_socket.listen() # 开启监听
print("[服务端]服务器启动完毕,在“%s”端口上监听,等待客户端连接...." % SERVER_POST)
# 当有客户端连接之后,那么会解除当前的阻塞状态,同时也可以获得客户端的Socket和地址
client_conn,address = server_socket.accept() # 进入到阻塞状态
with client_conn: # 进行客户端的处理
print("[服务端]客户端连接到服务器端,客户端的地址为:%s、连接端口:%s" % address)
while True: # 不断地进行信息的接收与响应
data = client_conn.recv(100).decode("UTF-8") # 接收客户端发送来的数据
if data.upper() == "BYEBYE": # 客户端发出结束指令
client_conn.send("exit".encode("UTF-8"))
break
else:
client_conn.send(("[ECHO]%s" % data).encode("UTF-8"))
if __name__ == "__main__":
main()

echo程序客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# coding : UTF-8
import socket
SERVER_HOST = "127.0.0.1" # 网络服务器的主机名称或IP地址
SERVER_PORT = 8080 # 服务器连接端口
def main(): # 主函数
with socket.socket() as client_socket: # 建立客户端的Socket
client_socket.connect((SERVER_HOST,SERVER_PORT)) # 连接服务端
while True: # 客户端一定要不断地与服务端进行交互
input_data = input("请输入要发送的数据(输入“byebye”结束):") # 键盘输入
client_socket.send(input_data.encode("UTF-8")) # 数据发送
echo_data = client_socket.recv(100).decode("UTF-8") # 回应数据
if echo_data.upper() == "EXIT": #结束
break # 断开循环
else:
print(echo_data) #输出服务端返回内容
if __name__ == "__main__":
main()

结果


[服务端]服务器启动完毕,在“8080”端口上监听,等待客户端连接….
[服务端]客户端连接到服务器端,客户端的地址为:127.0.0.1、连接端口:22242

进程已结束,退出代码0


请输入要发送的数据(输入“byebye”结束):hai
[ECHO]hai
请输入要发送的数据(输入“byebye”结束):Nihaonihao
[ECHO]Nihaonihao
请输入要发送的数据(输入“byebye”结束):hahah
[ECHO]hahah
请输入要发送的数据(输入“byebye”结束):byeBye

进程已结束,退出代码0


telnet测试

对于当前的服务端程序如果想要测试,简单点可以直接通过telnet命令来完成:

telnet localhost 8080

如果使用telnet进行内容发送的话,每当用户输入完一个内容之后就会立即将此内容发送到服务端,而且windows中的命令行本身使用的是GBK编码,所以自然会出现乱码的问题,但是如果使用telnet可以正常的连接,就意味着自定义的客户端一定可以连接,可以测试服务端是否正确。

处理服务端并发

此时的程序已经完美的实现了一个Socket程序的客户端,并且该客户端是基于TCP协议的,但是对于当前的服务器来讲存在一个重大的性能问题:采用的是单进程的处理模型完成的客户端请求。

在当前程序执行的过程之中,如果服务端已经有客户端进行连接了,那么整个的主进程就都为当前的客户端进行服务了,如果此时还有其他的客户端要想进行连接使用,由于主进程已经被占用,那么就意味着其它的用户是无法进行客户端操作的。

即当前的程序采用了单进程的模式运行。

在整个的程序之中。只需要修改服务端的程序实现类即可,在服务端追加上多进程的处理方式,即:每当有一个新的用户连接到服务器端之后就可以将其进行一个进程的包装处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# coding : UTF-8
import socket,multiprocessing
SERVER_HOST = "127.0.0.1"
SERVER_POST = 8080 # 服务绑定端口
def echo_handle(client_conn,address):
with client_conn:
print("[服务端]客户端连接到服务器端,客户端的地址为:%s、连接端口:%s" % address)
while True: # 不断地进行信息的接收与响应
data = client_conn.recv(100).decode("UTF-8") # 接收客户端发送来的数据
if data.upper() == "BYEBYE": # 客户端发出结束指令
client_conn.send("exit".encode("UTF-8"))
break
else:
client_conn.send(("[ECHO]%s" % data).encode("UTF-8"))
def main(): # 主函数
# socket网络服务在每一次处理完成之后一定要使用close()方法进行关闭,所以可以利用with结构进行定义
with socket.socket() as server_socket: # 创建了一个服务端的Socket
server_socket.bind((SERVER_HOST,SERVER_POST)) # 绑定本机的8080端口
server_socket.listen() # 开启监听
print("[服务端]服务器启动完毕,在“%s”端口上监听,等待客户端连接...." % SERVER_POST)
while True: # 不断地进行请求的接收
# 当有客户端连接之后,那么会解除当前的阻塞状态,同时也可以获得客户端的Socket和地址
client_conn, address = server_socket.accept() # 进入到阻塞状态
process = multiprocessing.Process(target=echo_handle,args=(client_conn,address,),
name="客户端进程-%s" % address[1]) #定义进程
process.start()
if __name__ == "__main__":
main()

引出高并发

当服务器端引入并发编程的概念之后,那么就可以同时进行多个客户端的请求处理,在开发行业内有一个“高并发”

指的就是连接的客户端比较多,所以这个时候如何可以处理好服务端处理性能就成了项目设计的关键。


py网络_echo程序模型笔记
https://blog.wangxk.cc/2020/02/05/py网络-echo程序模型笔记/
作者
Mike
发布于
2020年2月5日
许可协议