栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python系列 之 socket模块底层网络接口 - TCP协议类型

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python系列 之 socket模块底层网络接口 - TCP协议类型

Python socket模块学习
  • socket模块
    • socket模块主要对象和方法
    • 服务端与多个客户端实现通信
      • 服务端
      • 客户端

socket模块 socket模块主要对象和方法
  1. 通过socket.socket()函数来创建 套接字对象:
# socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
s = socket.socket(family=AF_INET, type=SOCK_STREAM)

socket.socket()函数参数:
摘自:Python文档 创建套接字

参数说明
family地址簇:AF_INET (默认)、AF_INET6、AF_UNIX、AF_CAN、AF_PACKET 或 AF_RDS
type套接字类型: SOCK_STREAM (默认)、SOCK_DGRAM、SOCK_RAW 或其他 SOCK_ 常量之一
proto协议号通常为零,可以省略,或者在地址簇为 AF_CAN 的情况下,协议号应为 CAN_RAW、CAN_BCM 或 CAN_ISOTP 之一
fileno如果指定了 fileno,那么将从这一指定的文件描述符中自动检测 family、type 和 proto 的值。如果调用本函数时显式指定了 family、type 或 proto 参数,可以覆盖自动检测的值。
  1. 将套接字绑定到 address:
# socket.bind(address)
s.bind(address=("127.0.0.1",9898))
参数说明
addressaddress 的格式取决于地址簇
  1. 启动一个服务器用于接受连接:
# socket.listen([backlog])
 s.listen(5)
  1. 接受一个连接:
# socket.accept()
# accept()方法返回值是一个tuple(conn, address)
conn, addr = s.accept()

socket.accept()方法返回值说明:

返回值说明
conn是一个新的套接字对象,请使用该套接字对象在连接上收发数据
address连接另一端的套接字所绑定的地址,客户端的 address tuple类型(IP,PORT)
  1. 连接到 address 处的远程套接字:
# socket.connect(address)
# 客户端向服务端发起连接
s.connect(("127.0.0.1",9898))
  1. 如果需要接收多个客户端的连接请求,那么每个连接都需要开启新的进程或者是线程
  2. 从套接字接收数据的方法:
# recv方法:socket.recv(bufsize[, flags])
# bufsize 指定一次接收的最大数据量
# 返回值是一个字节对象,表示接收到的数据
data_bytes = conn.recv(1024)
# recvfrom方法:socket.recvfrom(bufsize[, flags])
# 返回值是一个tuple(bytes, address)
# bytes 是字节对象,表示接收到的数据,address 是发送端套接字的地址
data_bytes, addr = conn.recvfrom(1024)

更多接收数据的方法 参考 Python文档

  1. 发送数据给套接字:
# send方法:socket.send(bytes[, flags])
# 返回已发送的字节数
# 应用程序要负责检查所有数据是否已发送,如果仅传输了部分数据,程序需要自行尝试传输其余数据
conn.send(b'Hi!')
conn.send(str("msg").encode("utf-8")

# sendall方法:socket.sendall(bytes[, flags])
# 与 send() 不同,本方法持续从 bytes 发送数据,直到所有数据都已发送或发生错误为止
# 成功后会返回 None。出错后会抛出一个异常,此时并没有办法确定成功发送了多少数据
conn.sendall(b'Hi!')
conn.sendall(str("msg").encode("utf-8")

# sendto方法:socket.sendto(bytes, address)
# 本套接字不应连接到远程套接字,而应由 address 指定目标套接字。
# 返回已发送的字节数

注意:服务端数据的收发需要使用accept()方法返回的套接字对象操作

更多发送数据的方法 参考Python文档

服务端与多个客户端实现通信 服务端

了解以上方法之后,利用套接字对象和方法来构建一个服务端:

# demo_socket_server.py文件

import logging
import socket
import threading
import time

logging.basicConfig(level=logging.DEBUG,
                    format="%(asctime)s>%(levelname)s>%(name)s>%(funcName)s>%(lineno)s>%(message)s")
logger = logging.getLogger(__name__)


class ServerClass(object):
    """docstring for ServerClass"""
    __HOST = "127.0.0.1"
    __PORT = 9898

    def __init__(self):
        # 创建 套接字对象 socket.socket(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)
        # 参数:family:地址簇  type:套接字类型
        self.__TCP_SOCKET = socket.socket(
            family=socket.AF_INET, type=socket.SOCK_STREAM)
        # 服务端的地址 address
        self.__ADDR = (ServerClass.__HOST, ServerClass.__PORT)
        # 用来交互的信息
        self.__MSG_DICT = {
            "1": ("讲笑话", "这是一个笑话"),
            "2": ("讲故事", "这是一个故事"),
            "3": ("学唱歌", "这是在唱歌"),
        }

    def start_server(self):
        """启动服务端方法"""
        with self.__TCP_SOCKET as s:
            # 将套接字绑定到 address
            s.bind(self.__ADDR)
            # 启动一个服务器用于接受连接 socket.listen([backlog])
            s.listen(5)
            logger.info("等待连接...")
            # 循环控制 用来等待客户端连接 以及保持连接状态
            while True:
                # 接受一个连接 返回值是一个 (conn, address)
                conn, addr = s.accept()
                # 多个客户端连接需要开启新的线程或者是进程
                th = threading.Thread(target=self.conn_client,
                                      args=(conn, addr), daemon=True)
                th.start()

    def conn_client(self, conn, addr):
        """连接客户端,并进行收发数据"""
        logger.info("正在与 %s 建立连接...", addr)
        with conn:
            # 如果有新的连接进来就 发送数据;
            conn.sendall(b'hi! %s %s n' %
                         tuple(map(lambda x: str(x).encode("utf-8"), addr)))
            time.sleep(0.8)
            conn.sendall(self.get_msg().encode("utf-8"))
            # 循环控制 使用accept()方法返回的套接字对象 收发数据
            while True:
                rec_data = conn.recv(1024).decode("utf-8")
                if not rec_data:
                    logger.info("与%s,断开连接...", addr)
                    time.sleep(0.5)
                    break
                # 如果客户端发送的数据可以识别 发送设置好的对应数据
                if rec_data in self.__MSG_DICT.keys():
                    conn.sendall(self.__MSG_DICT[rec_data][1].encode("utf-8"))
                else:
                    conn.sendall("不知道你在说什么".encode("utf-8"))

    def get_msg(self):
        """构造发送数据的格式"""
        msg_str = "可以为您提供一下服务:n"
        for k, v in self.__MSG_DICT.items():
            msg_str += k + " : " + v[0] + "n"
        return msg_str

if __name__ == '__main__':
    ServerClass().start_server()

然后启动服务端:
CMD进入到demo_socket_server.py同目录下,输入:

Python demo_socket_server.py

客户端

客户端的构建比服务端相对简单一些:

# demo_socket_client.py 文件
import logging
import time
import socket

logging.basicConfig(level=logging.DEBUG,
                    format="%(asctime)s>%(levelname)s>%(name)s>%(funcName)s>%(lineno)s>%(message)s")
logger = logging.getLogger(__name__)


class ClientClass(object):
    """docstring for ClientClass"""
    __HOST = "127.0.0.1"
    __PORT = 9898

    def __init__(self):
        self.__TCP_SOCKET = socket.socket(
            family=socket.AF_INET, type=socket.SOCK_STREAM)
        # 服务端的地址 address
        self.__ADDR = (ClientClass.__HOST, ClientClass.__PORT)

    def start_client(self):
        with self.__TCP_SOCKET as s:
            # 链接服务端地址
            s.connect(self.__ADDR)
            # 接收服务端发送来的数据
            recv_data = s.recv(1024).decode("utf-8")
            logger.info(recv_data)
            # 循环控制 保持和服务端通讯 收发数据
            while True:
                recv_data = s.recv(1024).decode("utf-8")
                logger.info(recv_data)
                time.sleep(0.5)
                send_data = input("请输入:")
                # 如果输入 quit 或者 exit 断开连接
                if send_data in ("quit", "exit"):
                    logger.info("正在退出...")
                    time.sleep(1.5)
                    break
                # 发送数据到服务端
                s.sendall(str(send_data).encode("utf-8"))
if __name__ == '__main__':
    ClientClass().start_client()

然后启动客户端:
CMD进入到demo_socket_client.py同目录下,输入:

Python demo_socket_server.py

开启一个客户端交互的效果:

下面是开启多个客户端交互的效果:

以上就是服务端向多个客户端之间接收发送数据的一个简单示例;可以实现服务端与多个客户端的交互。
但是还没有实现怎么让各个客户端之间可以进行通信,
下面要去学习如何能让各个客户端之间能够进行通信;学完了再抽空发上来。

主要参考资料来源:
廖雪峰的官方网站 - 网络编程 - TCP编程
Python 文档 : socket — 底层网络接口

如果有什么不对的地方,欢迎指正!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/664765.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号