说明
TCP 服务器是web后端开发必须学习的一环,此文章记录了我个人在学习python web开发过程中开发SocketServer的流程
Socket通信流程
网上找的图
逐步实现SocketServer
实现单次Soket Server与Client逻辑
依照以上述逻辑,使用python 标准库socket 模块实现单次接收/发送的Server/Client.
注:开始未将代码写成类是应为个人觉得OOP主要用来复用代码、解耦、抽象化复杂对象,对于第一步来说,使用类反而会让整个TCPServer创建流程不够直观。因此我会在后面需要的步骤将其重构为类
socket构造参数
参数 | 值 | 含义 |
---|---|---|
family | 默认为AF_INET | 协议簇,指定socket使用的协议,默认使用IPv4协议簇 |
type | 默认值未SOCKET_STREAM | 指定套接字类型,默认为流式套接字 |
proto | 默认值为0 | 指定套接字使用协议簇中的哪个协议,默认为TCP协议 |
fileno | 默认值为None | 指定socket打开的文件描述符 |
socket常用方法
方法 | 参数 | 含义 |
---|---|---|
bind() | address | 绑定socket到特点的ip和port上,形式为(‘127.0.0.1’, 80) |
listen() | 开始监听请求 | |
accept() | 接收请求,在未收到请求时阻塞 | |
send() | bytes、flags(可选) | 发送二进制数据,flags是一系列标志,可以控制发送的行为 |
rcev() | buffersize, flags(可选) | 指定接收缓冲区的大小,flags可控制接收行为 |
其他的方法不列举了,以后用到在写.
Code
- Client Code
#!/usr/bin/env python3
# encoding: utf-8
from socket import socket, AF_INET, SOCK_STREAM
def client(server_addr, msg):
"""
This function is a simple client to connect to TCPserver.
Args:
server_addr: String of Server IP address.
msg: The message that you want to send to server.It't type can
be str or bytes
"""
with socket(AF_INET, SOCK_STREAM) as sock # TCP/IPv4 Socket
sock.connect(server_addr)
if not isinstance(msg, bytes):
msg = bytes(msg, 'utf-8')
sock.send(msg)
data = sock.recv(4096)
print(data.decode('utf-8'))
if __name__ == '__main__':
client(('127.0.0.1', 8080), "I'm client.")
- ServerCode
#!/usr/bin/env python3
# encoding: utf-8
from socket import socket as Socket, AF_INET, SOCK_STREAM
from sys import exit, stderr
import logging
logging.basicConfig(
level=logging.INFO,
stream=stderr,
format="[%(levelname)s] %(asctime)s %(message)s"
)
log = logging.getLogger('SocketServer')
def check_addr(address):
"""
Check server address format
Not complete. TODO
"""
# check address
if len(address) < 2:
exit("You miss ip address or port.")
ip_addr, port = address
# Check port format
if isinstance(port, str):
try:
port = int(port)
except ValueError:
exit("Error Port Number: %s" % port)
return (ip_addr, port)
def recv_msg(socket):
"""Receive message from client"""
data = socket.recv(4096)
if isinstance(data, bytes):
data = data.decode('utf-8')
log.info("The receive data from client is: %s", data)
def send_msg(socket, msg):
"""Send message to client"""
socket.send(bytes(msg, 'uft-8'))
log.info("Send '%s' to client", msg)
def server(address=None, *, ip_addr=None, port=None):
"""
This is a simple TcpServer.It can receive data once from client.
Args:
ip_addr: String of ip address which server bind.
port: The port number which server bind. Type can be int or str.
address: Tuple like ('127.0.0.1', 80). Contain ip_addr and port. If
you use ip_addr or port with address param, it will override these.
"""
if not address:
address = (ip_addr, port)
address = check_addr(address)
with Socket(AF_INET, SOCKET_STREAM) as socket:
socket.bind(address)
s, _ = socket.accept()
recv_msg(s)
send_msg(s, 'Hello')
log.info("The Tcp Server close.")
if __name__ == "__main__":
server(('127.0.0.1', 8080))
接下来的计划
下面这些问题将在下一篇文章中解决
- 实现服务端接收多个client访问
- 当server处理程序消耗时间长时提高server处理效率