当前位置 : 主页 > 编程语言 > python >

#yyds干货盘点#Python之TCP UDP

来源:互联网 收集:自由互联 发布时间:2022-06-15
一、客户端/服务器架构 硬件C/S架构(打印机) 软件C/S架构(web服务) server端要求: 力求一直提供服务 要绑定一个唯一的地址,客户端可以明确的找到 二、基于tcp协议的简单套接字

一、客户端/服务器架构

  • 硬件C/S架构(打印机)
  • 软件C/S架构(web服务)
  • server端要求:
  • 力求一直提供服务
  • 要绑定一个唯一的地址,客户端可以明确的找到
  • 二、基于tcp协议的简单套接字

  • Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它时一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Scoket接口后面
  • 基于文件类型的套接字家族
  • AF_UNIX
  • AF_INET(基于网络通信)
  • 套接字的工作流程
  • socket()模块函数用法importsocketsocket.socket(socket_family,socket_type,protocal=0)socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为0。获取tcp/ip套接字 tcpSock =socket.socket(socket.AF_INET,socket.SOCK_STREAM) 获取udp/ip套接字 udpSock =socket.socket(socket.AF_INET,socket.SOCK_DGRAM) 由于socket模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用'from socket import *',我们就把socket模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。例如tcpSock =socket(AF_INET, SOCK_STREAM)
  • 服务端套接字函数
  • 客户端套接字函数
  • 公用用途的套接字函数
  • 代码示例
  • """
    tcp服务端
    """
    import socket

    IP_ADDR = ('127.0.0.1', 8001)
    # 创建服务器套接字
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 加入一条socket配置,重用ip和端口
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    # 把地址绑定到套接字
    sock.bind(IP_ADDR)

    # 监听链接
    sock.listen(5)

    while True: # 服务器无限循环
    conn, address = sock.accept() # 接受客户端链接
    print(address)
    while True: # 通信循环
    msg = conn.recv(1024) # 对话(接收)
    conn.send(msg.upper()) # 对话(发送)
    conn.close()
    sock.close()


    """
    tcp客户端
    """
    import socket
    IP_ADDR = ('127.0.0.1', 8001)
    # 创建服务器套接字
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 尝试连接服务器
    sock.connect(IP_ADDR)
    while True:
    cmd = input('>>>').strip()
    sock.send(cmd.encode('utf-8')) # 对话(发送/接收)

    msg = sock.recv(1024)
    print(msg)
    sock.close()
  • 6、关于套接字conn, address = phone.accept()中conn的内容
  • import socket

    phone = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    phone.bind(('127.0.0.1', 8080))
    phone.listen(5)
    while True:
    conn, address = phone.accept()
    print(conn)
    print(address)
    while True:
    data = conn.recv(1024)
    print(data)
    conn.send(data.upper())
    conn.close()
    conn.close()

    客户端输出数字后运行结果:
    <socket.socket fd=536, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 8080), raddr=('127.0.0.1', 56964)>
    ('127.0.0.1', 56964)
    b'da'
    b'dasdasd'

    二、粘包的现象

  • 只有TCP有粘包的现象,UDP永远不会粘包,粘包的问题是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据造成的
  • TCP是面向连接的,面向流的,提供高可靠性服务。收发两端(客户端和服务器端)都要有--成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方
  • UDP是无连接的,面向消息的,提供高效率服务,不会使用块的合并优化算法
  • 自制报头解决粘包问题
  • 报头(真实数据的描述信息,数字不能编码成bstyp格式
  • 三、多线程编程

  • 基于tcp协议的socketserver
    • 基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环
    • socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题)
    • server类
    • request类
    • 继承关系
    import socketserver

    class FTPserver(socketserver.BaseRequestHandler):
    def handle(self):
    print('dasdas',self)
    print(self.request) # self.request = conn
    while True: # 通信循环
    data = self.request.recv(1024)
    print(data)
    self.request.send(data.upper())

    if __name__ == '__main__':
    obj = socketserver.ThreadingTCPServer(('127.0.0.1', 8080), FTPserver)
    obj.serve_forever() # 链接循环
  • 分析socketserver源码
  • 与通信有关的,BaseRequestHandler,StearmRequsetHandler,DatagramRequestHandler
  • 以下列代码为例:
  • ftpserver = socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer) ftpserver.server_forever()
  • 源码分析总结:
  • 基于TCP的socketserver我们自己定义的类中的
    • self.server即套接字对象
    • self.request即一个链接
    • self.client_address即客户端地址

    基于UDP的socketserver我们自己定义的类中的

  • 面向对象的网络编程
  • 服务器端
  • """ 面向对象的网络编程服务器端 """import socketclassMyServer: address_family = socket.AF_INET# socket_type = socket.SOCK_STREAM listen_num =5receive_pack_size =1024coding ='utf-8'decoding ='gbk'def__init__(self, ip_address, bind_and_activate=True):self.ip_address = ip_addressself.socket = socket.socket(self.address_family,self.socket_type)ifbind_and_activate:try:self.server_bind()self.server_activate()except:self.server_close()defserver_bind(self):self.socket.bind(self.ip_address)self.ip_address =self.socket.getsockname()defserver_activate(self):self.socket.listen(self.listen_num)defserver_close(self):self.socket.close()defget_request(self):returnself.socket.accept() @staticmethoddefclose_request(request): request.close()defrun(self):whileTrue:self.conn,self.client_address =self.get_request() print('starting...')whileTrue:data =self.conn.recv(self.receive_pack_size)self.conn.send(data)server1 = MyServer(('127.0.0.1',8080))server1.run()

  • 上一篇:while循环基本语法
    下一篇:没有了
    网友评论