• python的socket编程


    socket

    Socket是网络编程的一个抽象概念。通常我们用一个Socket表示“打开了一个网络链接”,而打开一个Socket需要知道目标计算机的IP地址和端口号,再指定协议类型即可。

    socket参数

    socket地址族

    socket.``AF_UNIX  unix本机进程间通信 
    socket.``AF_INET  ipv4
    socket.``AF_INET6  ipv6
    

    socket类型

    socket.``SOCK_STREAM  TCP
    socket.``SOCK_DGRAM   UDP
    socket.``SOCK_RAW    #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。
    socket.``SOCK_RDM    #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
    socket.``SOCK_SEQPACKET #不使用了
    

    socket方法

    socket.socket`(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None)

    socket.``accept()

    socket.``bind(address)

    socket.``close()

    socket.``getblocking()

    socket.``setblocking(flag)

    socket.``listen([backlog])

    socket.``send(bytes[, flags])

    socket.``sendall(bytes[, flags])

    socket.``sendto(bytes, address)

    socket.``sendto(bytes, flags, address)

    socket.``recv(bufsize[, flags])

    socket.``recvfrom(bufsize[, flags]))

    TCP编程

    TCP客户端和服务器端的交互过程

    1559094035846

    注意:3.7.3测试多个TCP客户端,当客户端非正常断开,服务器程序也会崩掉

    例子1:简单的ssh的socket服务器客户端

    有几个问题需要注意的:

    • 问题1:socket每次接收和发送都有最大数据量限制的,发送的数据最大量的限制 就是缓冲区能缓存的数据的最大量。
    • 问题2:粘包问题,即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里,等缓冲区满了、或者数据等待超时了,数据才会被send到客户端,这样就把好几次的小数据拼成一个大数据,统一发送到客户端了,这么做的目地是为了提高io利用效率,一次性发送总比连发好几次效率高嘛。 但也带来一个问题,就是“粘包”,即2次或多次的数据粘在了一起统一发送了。
    • 解决办法:
    • 1.服务器发送数据包的大小,再发送数据包,客户端根据数据包的大小判断数据是否完全接收
    • 2.两次send出现的粘包问题
      • 方法1,time.sleep(0.5)秒,缓存区超时,就会把数据发送给客户端(不建议)
      • 方法2,在两次send之间,服务器设置一个rev,客户端设置一个send。在客户端不发送确认报文。服务器端不会主动的发送第2次的sendall数据,从而达到两次send的数据隔开。
    #客户端
    import socket
    
    if __name__ == '__main__':
        server_ip = "localhost"
        server_port = 9999
        client = socket.socket()
    
        client.connect((server_ip, server_port))
        while True:
            msg = input(">>:").strip()
            if not msg:
                continue
            client.send(msg.encode('utf-8'))
            res_recv_size = client.recv(1024).decode()
            client.send("ACK应答".encode("utf-8"))
            total_res_size = int(res_recv_size)
            print("收到指令结果的大小:%s" % total_res_size)
            recv_res_size = 0
            cmd_res = b''
            while recv_res_size != total_res_size:
                data = client.recv(1024)
                recv_res_size += len(data)
                cmd_res += data
                print(recv_res_size)
            else:
                print("数据收完了!!")
                print(cmd_res.decode())
    
    
        client.close()
        
    #服务器端
    import socket
    import os
    if __name__ == '__main__':
        server = socket.socket()
        server.setblocking(True)
        server.bind(("localhost", 9999))
        server.listen(5)
        while True:
            print("等待新连接。。。")
            conn, addr = server.accept()
            print("新连接接入", addr)
            while True:
                data = conn.recv(1024)
                if not data:
                    print("客户端断开连接")
                    break
                print("收到数据%s" % data)
                res = os.popen(data.decode()).read()
                if len(res):
                    conn.send(str(len(res)).encode('utf-8'))
                    print("等待客户ack应答...")
                    client_final_ack = conn.recv(1024)  # 等待客户端响应
                    print("客户应答:", client_final_ack.decode())
                    conn.sendall(res.encode("utf-8"))
                else:
                    conn.send(b"command error")
        server.close()
    

    UDP编程

    #服务器端
    import socket
    
    if __name__ == '__main__':
        server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        server.bind(("localhost", 9999))
        data, addr = server.recvfrom(1024)
        print("收到数据:", data.decode())
        print("发送人:", addr)
        server.sendto(data, addr)
        server.close()
        
    #客户端
    import socket
    
    if __name__ == '__main__':
        client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        data = b'hello world'
        HOST, PORT = "localhost", 9999
        client.sendto(data, (HOST, PORT))
        data, addr = client.recvfrom(1024)
        print(data.decode(), addr)
        client.close()
    

    socketserver

    socketserver — A framework for network servers

    同步

    • class socketserver.``TCPServer(server_address, RequestHandlerClass, bind_and_activate=True)

      This uses the Internet TCP protocol, which provides for continuous streams of data between the client and server. If bind_and_activate is true, the constructor automatically attempts to invoke server_bind() andserver_activate(). The other parameters are passed to the BaseServer base class.

    • class socketserver.``UDPServer(server_address, RequestHandlerClass, bind_and_activate=True)

      This uses datagrams, which are discrete packets of information that may arrive out of order or be lost while in transit. The parameters are the same as for TCPServer.

    • class socketserver.``UnixStreamServer(server_address, RequestHandlerClass, bind_and_activate=True)

    • class socketserver.``UnixDatagramServer(server_address, RequestHandlerClass, bind_and_activate=True)

      These more infrequently used classes are similar to the TCP and UDP classes, but use Unix domain sockets; they’re not available on non-Unix platforms. The parameters are the same as for TCPServer.

    异步

    • class socketserver.``ForkingTCPServer
    • class socketserver.``ForkingUDPServer
    • class socketserver.``ThreadingTCPServer
    • class socketserver.``ThreadingUDPServer

    1559097811251

    简单TCP的sockeserver

    #服务器端
    import socketserver
    
    class Myhandle(socketserver.BaseRequestHandler):
        def handle(self):
            self.data = self.request.recv(1024).decode()
            print(self.data)
            self.request.sendall(self.data.upper().encode("utf-8"))
    
    if __name__ == '__main__':
        HOST, PORT = "localhost", 9999
        server = socketserver.TCPServer((HOST, PORT), Myhandle) #单线程
        # server = socketserver.ThreadingTCPServer((HOST, PORT), Myhandle)  #多线程
        server.serve_forever()
        
    #客户端
    import socket
    
    if __name__ == '__main__':
        server_ip = "localhost"
        server_port = 9999
        client = socket.socket()
    
        client.connect((server_ip, server_port))
        while True:
            msg = input(">>:").strip()
            if not msg:
                continue
            client.send(msg.encode('utf-8'))
            data = client.recv(1024)
            print(data.decode())
    
    
        client.close()
    
  • 相关阅读:
    C语言main函数参数解析代码模板
    C语言函数指针复习小程序
    反转链表
    (Mingw32环境下)C语言使用库函数分配内存,按指定字节对齐
    Scrum meeting 3
    胆大妄为【DDWW】 Scrum meeting 2
    胆大妄为【DDWW】 Scrum meeting 1
    胆大妄为【DDWW】 《实验八 团队作业4:团队项目需求建模与系统设计》
    胆大妄为【DDWW】 实验七 团队作业3:团队项目需求分析与原型设计
    胆大妄为【DDWW】 实验六 团队作业2 :西北师范大学毕业生就业信息管理系统
  • 原文地址:https://www.cnblogs.com/akiz/p/11144326.html
Copyright © 2020-2023  润新知