• 第八节


    python3 socket编程

    Socket(翻译为套接字, 我觉得很挫),是操作系统内核中的一个数据结构,它是网络中的节点进行相互通信的门户。它是网络进程的ID。网络通信,归根到底还是进程间的通信(不同计算机上的进程间通信, 又称进程间通信, IP协议进行的主要是端到端通信)。在网络中,每一个节点(计算机或路由)都有一个网络地址,也就是IP地址。两个进程通信时,首先要确定各自所在的网络节点的网络地址。但是,网络地址只能确定进程所在的计算机,而一台计算机上很可能同时运行着多个进程,所以仅凭网络地址还不能确定到底是和网络中的哪一个进程进行通信,因此套接口中还需要包括其他的信息,也就是端口号(PORT)。在一台计算机中,一个端口号一次只能分配给一个进程,也就是说,在一台计算机中,端口号和进程之间是一一对应关系。
    所以,使用端口号和网络地址的组合可以唯一的确定整个网络中的一个网络进程.
    每一个socket都用一个半相关描述{协议、本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述{协议、本地地址、本地端口、远程地址、远程端口}来表示。socket也有一个类似于打开文件的函数调用,该函数返回一个整型的socket描述符,随后的连接建立、数据传输等操作都是通过socket来实现的

    流程描述socket 

      tcp/ip send,recv

      udp

    family address

      AF.NET  ipv4

      AF.INET6

      AF.UNIX  local

    socket protocol type

      SOCK_STREAM tcp/ip

      SOCK_DGREAM 数据报式socket,udp

    server = socket.socker(AF_INET,SOCK_STREAM)
    
    server.bind(ip_address,port)
    
    server.listen()
    
    while True:
    
      conn,addr = server.accept()  #开始堵塞
    
      while True:
    
        print("new conn")
    
        date = conn.recv(1024)  #官方建议不超过8192K
    
        if not data:break
    
        print(data)
    
        conn.send(data.upper())
    服务端
    client = socket.socket()
    
    client.connect(("server_ip",port))
    
    client.send((data))
    
    client.recv(data)
    客户端
    TCP通信的基本步骤如下:
    服务端:socket---bind---listen---while(True){---accept---recv---send----}---close
    客户端:socket------------------------------------connect---send---recv-------close

    socket函数

    server = socket.socket()
    
    server.recv() 
    server.send()
    server.close()
    server.close()
    server.listen()
    server.bind()
    server.type()
    server.accept()  #等待一个进来的连接,返回一个表示连接的新socket和客户端ip。对于ip docket来说,地址信息是一对(hostaddr,port)
    server.connect_ex()
    server.detath()
    server.dupv()
    server.family()
    server.fileno()
    server.get_inheritable()
    server.getpeername()
    server.getsockname()
    server.gettimeout()
    server.makefile()  #
    server.recv_into()
    server.recvfrom()
    server.sendall()
    server.sendto()
    server.sendfile(self, file, offset=0, count=None)  #通过使用高性能的os.sendfile()发送一个文件,并返回发送的字节总数。文件必须是一个标准的二进制打开文件,如果文件不可达,或者文件不是标准的文件,socket.send()会被使用。
    server.settimeout()
    server.shutdown()
    server.timeout()

     利用socket实现简单的ssh服务器与客户端

    import socket,os
    
    server =  socket.socket()
    server.bind(("localhost",9999))
    
    server.listen()
    
    while True:
        conn,addr = server.accept()
        print("new conn:",addr)
        while True:
            print("等待新指令")
            data = conn.recv(1024)
            if not data:
                print("客户端已断开")
                break
            print("执行新指令:",data)
            cmd_res = os.popen(data.decode()).read()
            print("before send:",len(cmd_res))
            if len(cmd_res) == 0:
                cmd_res = "cmd has no output..."
            conn.send(str(len(cmd_res.encode())).encode())
            cilent_ack = conn.recv(1024)
            print("cilent has already receive....")
            conn.send(cmd_res.encode())
            print("send done")
    
    server.close()
    socket ssh server
    import socket,os
    client = socket.socket()
    
    client.connect(("localhost",9999))
    
    while True:
        cmd = input(">>:").strip()
        if len(cmd) == 0: continue
        client.send(cmd.encode("utf-8"))
        cmd_res_size = client.recv(1024)
        client.send("可以发送数据了".encode())
        received_size = 0
        received_data = b""
        while received_size < int(cmd_res_size.decode()):
            data = client.recv(1024)
            received_size += len(data)
            received_data += data
        else:
            print("cmd res receive done...",received_size)
            print(received_data.decode())
    
    client.close()
    socket ssh client

     利用socket实现简单的ftp文件下载

    import socket,os,hashlib
    
    server =  socket.socket()
    server.bind(("localhost",9999))
    
    server.listen()
    
    while True:
        conn,addr = server.accept()
        print("new conn:",addr)
        while True:
            print("等待新指令")
            data = conn.recv(1024)
            if not data:
                print("客户端已断开")
                break
    
            cmd,filename = data.encode().split()
            print(filename)
            if  os.path.isfile(filename):
                f = open(filename,"rb")
                m = hashlib.md5()
                file_size = os.stat(filename).st_size
                conn.send(str(file_size).encode())
                conn.recv(1024)
                for line in f:
                    m.update(line)
                    conn.send(line)
                print("file md5",m.hexdigest())
                f.close()
                conn.send(m.hexdigest().encode())
    
            print("send done")
    
    server.close()
    ftp server
    import socket,os,hashlib
    client = socket.socket()
    
    client.connect(("localhost",9999))
    
    while True:
        cmd = input(">>:").strip()
        if len(cmd) == 0: continue
        if cmd.startswith("get"):
            client.send(cmd.encode())
            server_respone = client.recv(1024)
            print("server respone:",server_respone)
            client.send(b"ready to recv file")
            file_total_size = len(server_respone.decode())
            received_size = 0
            filename = cmd.split()[1]
            f = open(filename +".new","wb")
            m = hashlib.md5()
            while received_size < file_total_size:
                if file_total_size - received_size > 1024:
                    size = 1024
                else:
                    size = file_total_size - received_size
                    print("last received size",size)
                data = client.recv(size)
                received_size += len(data)
                m.update(data)
                f.write(data)
            else:
                new_file_md5 = m.hexdigest()
                print("file rece done",received_size,file_total_size)
                f.close()
    
            server_file_md5 = client.recv(1024)
            print("server file md5:",server_file_md5)
    
    client.close()
    ftp client

     sockerserver介绍

    
    
    The classes in this module favor the server type that is simplest to
    write: a synchronous TCP/IP server. This is bad class design, but
    save some typing. (There's also the issue that a deep class hierarchy
    slows down method lookups.)

    There are five classes in an inheritance diagram, four of which represent
    synchronous servers of four types:

    +------------+
    | BaseServer |
    +------------+
    |
    v
    +-----------+ +------------------+
    | TCPServer |------->| UnixStreamServer |
    +-----------+ +------------------+
    |
    v
    +-----------+ +--------------------+
    | UDPServer |------->| UnixDatagramServer |
    +-----------+ +--------------------+
    Note that UnixDatagramServer derives from UDPServer, not from
    UnixStreamServer -- the only difference between an IP and a Unix
    stream server is the address family, which is simply repeated in both
    unix server classes.

    Forking and threading versions of each type of server can be created
    using the ForkingMixIn and ThreadingMixIn mix-in classes. For
    instance, a threading UDP server class is created as follows:

    class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass

    The Mix-in class must come first, since it overrides a method defined
    in UDPServer! Setting the various member variables also changes
    the behavior of the underlying server mechanism.

    To implement a service, you must derive a class from
    BaseRequestHandler and redefine its handle() method. You can then run
    various versions of the service by combining one of the server classes
    with your request handler class.

    The request handler class must be different for datagram or stream
    services. This can be hidden by using the request handler
    subclasses StreamRequestHandler or DatagramRequestHandler.

    Of course, you still have to use your head!

    For instance, it makes no sense to use a forking server if the service
    contains state in memory that can be modified by requests (since the
    modifications in the child process would never reach the initial state
    kept in the parent process and passed to each child). In this case,
    you can use a threading server, but you will probably have to use
    locks to avoid two requests that come in nearly simultaneous to apply
    conflicting changes to the server state.

    On the other hand, if you are building e.g. an HTTP server, where all
    data is stored externally (e.g. in the file system), a synchronous
    class will essentially render the service "deaf" while one request is
    being handled -- which may be for a very long time if a client is slow
    to read all the data it has requested. Here a threading or forking
    server is appropriate.

    In some cases, it may be appropriate to process part of a request
    synchronously, but to finish processing in a forked child depending on
    the request data. This can be implemented by using a synchronous
    server and doing an explicit fork in the request handler class
    handle() method.

    Another approach to handling multiple simultaneous requests in an
    environment that supports neither threads nor fork (or where these are
    too expensive or inappropriate for the service) is to maintain an
    explicit table of partially finished requests and to use a selector to
    decide which request to work on next (or whether to handle a new
    incoming request). This is particularly important for stream services
    where each client can potentially be connected for a long time (if
    threads or subprocesses cannot be used).

    Future work:
    - Standard classes for Sun RPC (which uses either UDP or TCP)
    - Standard mix-in classes to implement various authentication
    and encryption schemes

    XXX Open problems:
    - What to do with out-of-band data?

    BaseServer:
    - split generic "request" functionality out into BaseServer class.
    Copyright (C) 2000 Luke Kenneth Casson Leighton <lkcl@samba.org>

    example: read entries from a SQL database (requires overriding
    get_request() to return a table entry from the database).
    entry is processed by a RequestHandlerClass.

     handle方法

    class BaseRequestHandler:
    
        """Base class for request handler classes.
    
        This class is instantiated for each request to be handled.  The
        constructor sets the instance variables request, client_address
        and server, and then calls the handle() method.  To implement a
        specific service, all you need to do is to derive a class which
        defines a handle() method.
    
        The handle() method can find the request as self.request, the
        client address as self.client_address, and the server (in case it
        needs access to per-server information) as self.server.  Since a
        separate instance is created for each request, the handle() method
        can define other arbitrary instance variables.
    
        """
    
        def __init__(self, request, client_address, server):
            self.request = request
            self.client_address = client_address
            self.server = server
            self.setup()
            try:
                self.handle()
            finally:
                self.finish()
    
        def setup(self):
            pass
    
        def handle(self):
            pass
    
        def finish(self):
            pass
    
    
    # The following two classes make it possible to use the same service
    # class for stream or datagram servers.
    # Each class sets up these instance variables:
    # - rfile: a file object from which receives the request is read
    # - wfile: a file object to which the reply is written
    # When the handle() method returns, wfile is flushed properly

    一个简单的socketserver

    import socketserver
    
    class MyTCPHandler(socketserver.BaseRequestHandler):
        def handle(self):
            while True:
                try:
                    self.data = self.request.recv(1024).strip()
                    print("{} wrote:".format(self.client_address[0]))
                    print(self.data)
                    self.request.send(self.data.upper())
                except ConnectionResetError as e:
                    print("err:",e)
                    break
    
    if __name__ == '__main__':
        HOST,PORT = "localhost",9999
        server = socketserver.TCPServer((HOST,PORT),MyTCPHandler)
        server.serve_forever()
    socketserver

      

  • 相关阅读:
    linux进程间通信--信号量
    linux进程间通信--信号通信
    linux进程间通信--管道通信
    探究守护进程及其错误日志处理
    探究wait与waitpid之间的那些事
    探究一下strtok的用法
    文件IO与标准IO探究及总结
    Linux 库的制作--动态库与静态库
    python基础使用
    linux正则表达式使用
  • 原文地址:https://www.cnblogs.com/ttyypjt/p/7414200.html
Copyright © 2020-2023  润新知