python之socket模块

前言

主要用于自己自学python后端的笔记

一、socket模块

Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

在这里主要学习利用socket完成TCP/IP通讯,首先需要生成两个对象,一个是客户端(client),一个是服务端(sever)。

1.服务端(sever)

步骤;
1.创建对象 .socket()
2.绑定ip地址与端口 .bind()
3.监听 .listen()
4.接收一个套接口接受的一个连接 .accept()
5.接收连接进来的数据 .recv()
6.发送连接进来的数据 .send()
代码如下:

import socket

server = socket.socket()
# 绑定要监控的界面
server.bind(("localhost", 6969))
# 监听
server.listen()
print("我要开始等电话了!")
while True:
    # 等电话打进来
    conn, adr = server.accept()
    while True:

        data = conn.recv(1024)
        print("接收:", data)
        if not data:
            print("host is lost")
            break
        conn.send(data.upper())

server.close()

代码解释:
server = socket.socket() #生成一个服务端
server.bind((“localhost”, 6969))# 绑定要监控的界面,元祖形式(ip地址,端口号)
server.listen() # 监听端口状态
conn, adr = server.accept() # 获取进来的对象是谁(conn),cnn为后数据传输通道,adr为ip地址
data = conn.recv(1024) # 接收数据,接收数据量为1024
conn.send(data) # 发送数据,需要编码endcode()

2.客户端(client)

步骤;
1.创建对象 .socket()
2.连接ip地址与端口 .connet()
3.接收进来的数据 .recv()
4.发送数据 .send()
代码如下:

import socket

client = socket.socket()
client.connect(('localhost', 6969))
while True:
    msg = input(">>:")
    if len(msg) == 0: continue
    client.send(msg.encode("utf-8"))
    data = client.recv(1024)
    print("数据:", data)

client.close()

代码解释:
client.connect((‘localhost’, 6969)) # 设置IP地址和端口,元组形式

3.数据格式问题

python默认数据格式为Unicode,在发送数据时,函数send()的参数类型是:Byte,需要将数据转换类型。
在这里插入图片描述

4.数据沾包

当连续的调用send()时,接收recv()有大小限制,发送的数据量大于接收的数据量,截断的数据储存在缓存器BUFF中,下一次数据在传输时,会优先传输上次截断的数据,从而发生了粘包。
为了避免这种错误,通过设计反馈,即发送数据后反馈给发送数据回来。发送中间夹杂着一次接收,避免了数据在缓冲中导致粘包。

5.数据完整接收

数据接收recv()有大小限制,在为了保证目标数据的完整性,数据发送前应当给客户端发送数据量大小,用于判断数据是否接收完全。但如果两次send()连续执行会产生粘包。

二、socketsever模块

socketserver本质是基于socket模块进行的一个封装,将多线程并发功能集成到一个新的模块里,就叫socketserver;它用来解决TCP套接字无法并发的问题,也就是无法一个服务端不能同时服务多个客户端的问题(UDP没有此问题,因为它不需要链接)。
socketserver中包含了两种类,一种为服务类(server class),一种为请求处理类(request handle class)

2.1 server类:处理链接

BaseServer 处理链接必须
TCPServer 处理流式(TCP)链接
UDPServer 处理数据报式(UDP)链接

2.2 request类:处理通信

BaseRequestHandler 处理通信
StreamRequestHandler 处理流式通信,即TCP
DatagramRequestHandler 处理数据报式通信,即UDP

2.3 socketsever服务端实现

步骤:
1、创建一个类,必须继承socketserver.BaseRequestHandler类
2、在该类中定义handle方法,其中self.request是获取的链接,self.client_address则是获取的地址
3.self.request.sendall(data) # 将受到的数据完整发送出去,返回none。

import socketserver

# 定义一个类,该类必须继承socketserver下的BaseRequestHandler类
class MyServer(socketserver.BaseRequestHandler):
    def handle(self):  # 必须定义一个handle方法
        print('conn is ', self.request)  # self.request是获取的链接,相当于conn
        print('addr is ', self.client_address)  # self.client_address则是获取的地址,相当于addr

        # 循环收发消息
        while True:
            try:  # 异常处理
                # 收消息
                data = self.request.recv(1024)  # 1024字节
                if not data: continue  # 如果是空就重新输入
                print('客户端发来的消息是:', data.decode('utf-8'), '\n')
                # 发消息
                self.request.sendall(data.upper())  # 将受到的数据转化为大写后发回客户端
            except Exception as e:
                print(e)  # 打印错误
                break


if __name__ == '__main__':
    host, port = 'localhost', 6969
    # 再将这样的功能实例化成一个对象sever
    # 第一个参数为服务端的ip地址,用元组传进;第二个参数是刚刚定义的那个类
    sever = socketserver.TCPServer((host, port), MyServer)
    sever.serve_forever()  # 永远,就是通信循环(链接循环)

多线程使用socketsever…ThreadingTCPServer,即可实现多线程通讯。

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2023年3月5日
下一篇 2023年3月5日

相关推荐