zoukankan      html  css  js  c++  java
  • python之网络编程

    基础版

    server code

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.bind(('127.0.0.1',8080))
    phone.listen(5)
    
    print('starting...')
    conn,client_addr=phone.accept()
    # print(phone)
    # print(conn)
    # print(client_addr)
    data=conn.recv(1024)
    print('客户端数据',data.decode('UTF-8'))
    conn.send(data.upper())
    conn.close()
    phone.close()
    

    client code

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1',8080))
    phone.send('hello world'.encode('utf-8'))
    data=phone.recv(1024)
    print(data)
    phone.close()
    

    基础版+循环执行

    sever code

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    print('starting...')
    conn,client_addr=phone.accept()
    print(client_addr)
    while True:
        # print(phone)
        # print(conn)
        # print(client_addr)
        data=conn.recv(1024)
        print('客户端数据',data.decode('UTF-8'))
        conn.send(data.upper())
    conn.close()
    phone.close()
    

    client code

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1', 8081))
    while True:
        msg=input('>> ')
        phone.send(msg.encode('utf-8'))
        data=phone.recv(1024)
        print(data)
    phone.close()
    

    server code bug fix

    上述server code代码有一个bug, 就是当client端断开的时候, 如果是linux操作系统, 会陷入一个死循环, 如果是windows系统则会报错ConnectionResetError, 这是因为上边的server code代码中, conn对象是一个服务端和客户端的双向数据通道, 当客户端强行关闭之后, 就会出现报错导致服务端不可用了

    • 这个bug在linux上处理起来就是在data=conn.recv(1024)加一个判断是否为空就可以了
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    print('starting...')
    conn,client_addr=phone.accept()
    print(client_addr)
    while True:
        # print(phone)
        # print(conn)
        # print(client_addr)
        data=conn.recv(1024)
        if not data:break
        print('客户端数据',data.decode('UTF-8'))
        conn.send(data.upper())
    conn.close()
    phone.close()
    
    • 这个bug在windows上处理起来就是在data=conn.recv(1024)加一个try...except就可以了
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    print('starting...')
    conn,client_addr=phone.accept()
    print(client_addr)
    while True:
        # print(phone)
        # print(conn)
        # print(client_addr)
        try:
            data=conn.recv(1024)
            print('客户端数据',data.decode('UTF-8'))
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()
    phone.close()
    

    上述client code代码有一个bug, 就是直接敲一个回车的时候, 客户端会卡主. 原因是当敲完回车之后, 代码会走到phone.send这一行, 这一行代码会给操作系统发一个空, 操作系统认为没有数据, 所以并不会发送给server端, 所以代码会一直停留在phone.recv这个位置等待接收数据, 这个bug处理起来也很简单, 同样加一个判断msg是否为空就可以了

    client code fix bug

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1', 8081))
    while True:
        msg=input('>> ')
        if not msg:continue
        phone.send(msg.encode('utf-8'))
        data=phone.recv(1024)
        print(data)
    phone.close()
    

    服务端可以连续接收请求版

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    while True:
        print('starting...')
        conn, client_addr = phone.accept()
        print(client_addr)
        while True:
            # print(phone)
            # print(conn)
            # print(client_addr)
            try:
                data=conn.recv(1024)
                print('客户端数据',data.decode('UTF-8'))
                conn.send(data.upper())
            except ConnectionResetError:
                break
        conn.close()
    phone.close()
    
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1', 8081))
    while True:
        msg=input('>> ')
        if not msg:continue
        phone.send(msg.encode('utf-8'))
        data=phone.recv(1024)
        print(data)
    phone.close()
    

    模拟ssh远程执行命令

    server code

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket,subprocess
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    while True:
        print('starting...')
        conn, client_addr = phone.accept()
        print(client_addr)
        while True:
            # print(phone)
            # print(conn)
            # print(client_addr)
            try:
                cmd=conn.recv(1024)
                res = subprocess.Popen(cmd.decode('gbk'), shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE
                                       )
                stdout=res.stdout.read()
                stderr=res.stderr.read()
                data=stdout+stderr
                conn.send(data)
            except ConnectionResetError:
                break
        conn.close()
    phone.close()
    

    client code

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1', 8081))
    while True:
        cmd=input('>> ')
        if not cmd:continue
        phone.send(cmd.encode('gbk'))
        data=phone.recv(1024)
        print(data.decode('gbk'))
    phone.close()
    

    解决粘包问题

    引入struct模块

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import struct
    res=struct.pack('i',111111)
    print(res,type(res),len(res))  #len(res)永远是4, 所以在客户端就可以先收4个字节来判断全部数据的字节大小
    
    obj=struct.unpack('i',res)
    print(obj[0])
    

    server code

    简单版

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket,subprocess
    import struct
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
    phone.bind(('127.0.0.1',8081))
    phone.listen(5)
    
    while True:
        print('starting...')
        conn, client_addr = phone.accept()
        print(client_addr)
        while True:
            # print(phone)
            # print(conn)
            # print(client_addr)
            try:
                cmd=conn.recv(1024)
                res = subprocess.Popen(cmd.decode('gbk'), shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE
                                       )
                stdout=res.stdout.read()
                stderr=res.stderr.read()
                data=stdout+stderr
                header=struct.pack('i',len(data))
                conn.send(header)
                conn.send(stdout)
                conn.send(stderr)
            except ConnectionResetError:
                break
        conn.close()
    

    client code

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    import socket
    import struct
    phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    phone.connect(('127.0.0.1', 8081))
    while True:
        cmd=input('>> ')
        if not cmd:continue
        phone.send(cmd.encode('gbk'))
        obj = phone.recv(4)
        total_size = struct.unpack('i',obj)[0]
        # print(total_size)
        recv_size=0
        recv_data=b''
        while recv_size < total_size:
            res=phone.recv(1024)
            recv_data+=res
            recv_size+=len(res)
        print(recv_data.decode('gbk'))
    phone.close()
    
  • 相关阅读:
    Windows下使用CMake编译SuiteSparse成VS工程
    【设计模式
    【设计模式
    vue过滤和复杂过滤
    el-tooltip 自定义样式
    el-table加表单验证
    使用Go env命令设置Go的环境
    面试官:GET 和 POST 两种基本请求方法有什么区别?
    解决 Vue 重复点击相同路由报错的问题
    利用promise和装饰器封装一个缓存api请求的装饰器工具
  • 原文地址:https://www.cnblogs.com/peitianwang/p/14234779.html
Copyright © 2011-2022 走看看