zoukankan      html  css  js  c++  java
  • 饮冰三年-人工智能-Python-19 Python网络编程

    Socket:套接字。作用:我们只需要安照socket的规定去编程,就不需要深入理解tcp/udp协议也可以实现

    1:TCP协议

    1.1  客户端服务端循环收发消息

    # 1:引入stock模块(导包)
    import socket
    #2:创建服务端对象
    tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #3:绑定接口地址和端口号
    ip_port=("127.0.0.1",8000)
    back_log=5
    buffer_size=1024
    tcp_server.bind(ip_port)
    #4: 开启监听(设置监听数量)
    tcp_server.listen(back_log)
    print("服务端开始运行了")
    # 5:准备接收消息
    conn, add = tcp_server.accept()
    while True:
        #6:接收消息
        data=conn.recv(buffer_size)
        print("客户端发送的消息是:",data.decode("utf-8"))
        #7:发送消息
        conn.send(data.upper())
    # 8:关闭连接
    conn.close()
    # 9:关闭服务端对象
    tcp_server.close()
    服务端
    #1:引入模块
    from socket import *
    #2:创建对象
    tcp_client = socket(AF_INET,SOCK_STREAM)
    #3:建立连接
    ip_port=("127.0.0.1",8000)
    buffer_size=1024
    tcp_client.connect(ip_port)
    while True:
        msg=input("请输入待发送的消息:")
        #4:发消息
        tcp_client.send(msg.encode("utf-8"))
        # 5:收消息
        data=tcp_client.recv(buffer_size)
        print("收到服务端传来的消息",data.decode("utf-8"))
    tcp_client.close()
    客户端

    1.2 服务端循环链接请求来收发消息

    # 1:引入stock模块(导包)
    import socket
    #2:创建服务端对象
    tcp_server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    #3:绑定接口地址和端口号
    ip_port=("127.0.0.1",8000)
    back_log=5
    buffer_size=1024
    tcp_server.bind(ip_port)
    #4: 开启监听(设置监听数量)
    tcp_server.listen(back_log)
    print("服务端开始运行了")
    while True:
        # 5:准备接收消息
        conn, add = tcp_server.accept()
        while True:
            # 客户端断开连接的时候会报错
            try:
                # 6:接收消息
                data = conn.recv(buffer_size)
                # 据说Linux系统即使客户端断开连接也不会抛异常,这是需要手处理一下
                if not data:break
                print("客户端发送的消息是:", data.decode("utf-8"))
                # 7:发送消息
                conn.send(data.upper())
            except Exception:
                break
        # 8:关闭连接
        conn.close()
    # 9:关闭服务端对象
    tcp_server.close()
    # 改进方向
    #     1:把5和8放入到循环中,这样就可以实现多连接了
    #     2:在内部连接中设置break方法
    服务端
    #1:引入模块
    from socket import *
    #2:创建对象
    tcp_client = socket(AF_INET,SOCK_STREAM)
    #3:建立连接
    ip_port=("127.0.0.1",8000)
    buffer_size=1024
    tcp_client.connect_ex(ip_port)
    while True:
        msg=input("请输入待发送的消息:")
        #如果不加这句,当输入换行时,服务器端会阻塞
        if len(msg)==0:
            continue
        #4:发消息
        tcp_client.send(msg.encode("utf-8"))
        # 5:收消息
        data=tcp_client.recv(buffer_size)
        print("收到服务端传来的消息",data.decode("utf-8"))
    tcp_client.close()
    客户端

     1.3 从代码层面解决 “通常每个套接字地址(协议/网络地址/端口)只允许使用一次。”问题,在bind前加下一句代码

    tcp_server.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

    2:UDP协议

    2.1  客户端服务端循环收发消息

    # 1:引入stock模块(导包)
    from socket import *
    from time import strftime
    #2:创建服务端对象
    udp_server =socket(AF_INET,SOCK_DGRAM)
    #3:绑定接口地址和端口号
    ip_port=("127.0.0.1",8000)
    back_log=5
    buffer_size=1024
    udp_server.bind(ip_port)
    print("服务端开始运行了")
    while True:
        while True:
            # 客户端断开连接的时候会报错
            try:
                # 6:接收消息
                data ,add= udp_server.recvfrom(buffer_size)
                print("客户端发送的消息是:", data.decode("utf-8"))
                # 7:发送消息
                time_fmt='%Y-%m-%d %X'
                data=strftime(time_fmt)
                udp_server.sendto(data.encode("utf-8"),add)
            except Exception:
                break
    
    # 9:关闭服务端对象
    udp_server.close()
    # udp与tcp的不同之处
    #     1:不需要连接s.listen()  监听和 s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来
    #     2:通过recvfrom()接收数据;sendto()发送数据
    #     3:既然没有连接,也就无所谓谁先启动,或者客户端关闭后是否会引发异常等情况
    服务端
    #1:引入模块
    from socket import *
    #2:创建对象
    udp_client = socket(AF_INET,SOCK_DGRAM)
    #3:建立连接
    ip_port=("127.0.0.1",8000)
    buffer_size=1024
    udp_client.connect_ex(ip_port)
    while True:
        msg=input("按任意键获取时间:")
        # 4:发消息
        udp_client.sendto(msg.encode("utf-8"), ip_port)
        # 5:收消息
        data, add = udp_client.recvfrom(buffer_size)
        print("收到服务端传来的时间", data)
    
    
    tcp_client.close()
    客户端

    3:练习

      3.1 远程操作

      需要使用subprocess模块  

    from socket import *
    import subprocess
    ip_port = ("127.0.0.1", 8089)
    back_log = 5
    buffer_size = 1024
    tcp_server = socket(AF_INET, SOCK_STREAM)
    tcp_server.bind(ip_port)
    tcp_server.listen(back_log)
    while True:
        conn, add = tcp_server.accept()
        print(add)
        while True:
            try:
                cmd = conn.recv(buffer_size);
                if not cmd:
                    conn.close()
                    break
                res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                       stderr=subprocess.PIPE,
                                       stdout=subprocess.PIPE,
                                       stdin=subprocess.PIPE,
                                       )
                err = res.stderr.read()
                if err:
                    cmd_res = err
                else:
                    cmd_res = res.stdout.read()
                #
                conn.send(cmd_res)
            except Exception as e:
                print(e)
                conn.close()
                break
        conn.close()
    top_server.close()
    TCP-Server-1.0
    from socket import *
    
    ip_port=("127.0.0.1", 8089)
    back_log = 5
    buffer_size = 1024
    tcp_client = socket(AF_INET, SOCK_STREAM)
    tcp_client.connect(ip_port)
    while True:
        cmd = input(">>: ").strip()
        if not cmd:
            continue
        if cmd == "quit":
            break
        tcp_client.send(cmd.encode("utf-8"))
        cmd_res = tcp_client.recv(buffer_size)
        print(cmd_res.decode("gbk"))
    tcp_client.close()
    TCP-Client-1.0

      会出现粘包现象:1:tcp-ip内部算法优化,会把短时间内几个小的send信息包在一起发送(tcp-ip的send本身没有界限)2:一次发送量大,一次接受不全

    from socket import *
    import subprocess
    ip_port = ("127.0.0.1", 8089)
    back_log = 5
    buffer_size = 1024
    tcp_server = socket(AF_INET, SOCK_STREAM)
    tcp_server.bind(ip_port)
    tcp_server.listen(back_log)
    while True:
        conn, add = tcp_server.accept()
        print(add)
        while True:
            try:
                cmd = conn.recv(buffer_size);
                if not cmd:
                    conn.close()
                    break
                res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                       stderr=subprocess.PIPE,
                                       stdout=subprocess.PIPE,
                                       stdin=subprocess.PIPE,
                                       )
                err = res.stderr.read()
                if err:
                    cmd_res = err
                else:
                    cmd_res = res.stdout.read()
                # 为了解决粘包的问题,可以在发送的时候先把长度发过去
                length=str(len(cmd_res)).encode("utf-8")
                conn.send(length)
                # 如果直接这么发的话,会出现由于tcp优化出现的粘包情况。
                client_s = conn.recv(buffer_size);
                print("===>",client_s)
                if client_s==b"ready":
                    conn.send(cmd_res)
            except Exception as e:
                print(e)
                conn.close()
                break
        conn.close()
    top_server.close()
    TCP-Server-2.0
    from socket import *
    
    ip_port=("127.0.0.1", 8089)
    back_log = 5
    buffer_size = 1024
    tcp_client = socket(AF_INET, SOCK_STREAM)
    tcp_client.connect(ip_port)
    while True:
        cmd = input(">>: ").strip()
        if not cmd:
            continue
        if cmd == "quit":
            break
        tcp_client.send(cmd.encode("utf-8"))
        res_length=tcp_client.recv(buffer_size);
    
        #把获取到的长度转化成intleiixng
        cmd_res=""
        if res_length:
            tcp_client.send("ready".encode("utf-8"))
            res_length = int(res_length.decode("gbk"))
            print(res_length)
            # 循环遍历接收
            while len(cmd_res)<res_length:
                cur_res=tcp_client.recv(buffer_size).decode("gbk")
                cmd_res = cmd_res+cur_res
                print(cur_res)
    tcp_client.close()
    TCP-client-2.0
    # 通过引入struct模块,编制一个报文长度,实现一次发送
    import struct
    from socket import *
    import subprocess
    ip_port = ("127.0.0.1", 8089)
    back_log = 5
    buffer_size = 1024
    tcp_server = socket(AF_INET, SOCK_STREAM)
    tcp_server.bind(ip_port)
    tcp_server.listen(back_log)
    while True:
        conn, add = tcp_server.accept()
        print(add)
        while True:
            try:
                cmd = conn.recv(buffer_size);
                if not cmd:
                    conn.close()
                    break
                res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                       stderr=subprocess.PIPE,
                                       stdout=subprocess.PIPE,
                                       stdin=subprocess.PIPE,
                                       )
                err = res.stderr.read()
                if err:
                    cmd_res = err
                else:
                    cmd_res = res.stdout.read()
                # 为了解决粘包的问题,可以在发送的时候先把长度发过去
                length=struct.pack("i",len(cmd_res))
                conn.send(length)
                conn.send(cmd_res)
                print(struct.unpack("i",length)[0])
            except Exception as e:
                print(e)
                conn.close()
                break
        conn.close()
    top_server.close()
    TCP-Service # 通过引入struct模块,编制一个报文长度,实现一次发送
    # 通过引入struct模块,编制一个报文长度,实现一次发送
    from socket import *
    import struct
    ip_port=("127.0.0.1", 8089)
    back_log = 5
    buffer_size = 1024
    tcp_client = socket(AF_INET, SOCK_STREAM)
    tcp_client.connect(ip_port)
    while True:
        cmd = input(">>: ").strip()
        if not cmd:
            continue
        if cmd == "quit":
            break
        tcp_client.send(cmd.encode("utf-8"))
    
        #把获取到的长度转化成intleiixng
        cmd_res=b''
        res_length = tcp_client.recv(4)
        length=struct.unpack("i",res_length)[0]
        # 循环遍历接收
        while len(cmd_res) < length:
            cur_res = tcp_client.recv(buffer_size)
            cmd_res = cmd_res + cur_res
        print(cmd_res.decode("gbk"))
    tcp_client.close()
    TCP-client-# 通过引入struct模块,编制一个报文长度,实现一次发送
    # 通过引入struct模块,实现一次发送
    # 通过socketServer实现并发
    import struct
    from socket import *
    import subprocess
    import socketserver
    
    
    ip_port = ("127.0.0.1", 8089)
    back_log = 5
    buffer_size = 1024
    
    # 定义一个实例化的类,主要用于收发消息
    class My_server(socketserver.BaseRequestHandler):
        def handle(self):
            try:
                while True:
                    # 收消息
                    cmd = self.request.recv(buffer_size)
                    if not cmd: break
                    res = subprocess.Popen(cmd.decode("utf-8"), shell=True,
                                           stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
                    err = res.stderr.read()
                    if err:
                        cmd_res = err
                    else:
                        cmd_res = res.stdout.read()
                    # 为了解决粘包的问题,可以在发送的时候先把长度发过去
                    length = struct.pack("i", len(cmd_res))
                    self.request.send(length)
                    self.request.sendall(cmd_res)
            except Exception as e:
                print(e)
    
    
    #通过线程创建对象
    if __name__=="__main__":
        s=socketserver.ThreadingTCPServer(ip_port,My_server)
        s.serve_forever()
    TCP-Service-4.0 通过socketServer实现并发
    # 通过引入struct模块,编制一个报文长度,实现一次发送
    from socket import *
    import struct
    ip_port=("127.0.0.1", 8089)
    back_log = 5
    buffer_size = 1024
    tcp_client = socket(AF_INET, SOCK_STREAM)
    tcp_client.connect(ip_port)
    while True:
        cmd = input(">>: ").strip()
        if not cmd:
            continue
        if cmd == "quit":
            break
        tcp_client.send(cmd.encode("utf-8"))
    
        #把获取到的长度转化成intleiixng
        cmd_res=b''
        res_length = tcp_client.recv(4)
        length=struct.unpack("i",res_length)[0]
        # 循环遍历接收
        while len(cmd_res) < length:
            cur_res = tcp_client.recv(buffer_size)
            cmd_res = cmd_res + cur_res
        print(cmd_res.decode("gbk"))
    tcp_client.close()
    TCP-client-4.0 通过socketServer实现并发

     4:FTP文件上传与下载

      4.1实现客户端与服务端的调通

      首先,创建两个文件夹FTP_server和FTP_client用于存放服务端和客户端的文件

      4.1.1 FTP_server

      创建一个bin文件,里面包含启动文件ftp_server.py

      4.1.1.1 bin文件  

    # 主要用于启动
    import os,sys
    # 此时的路径是当前执行文件的路径,相当于当前的bin目录下寻找core中的main方法
    PATH=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.append(PATH)
    from core import main
    
    if __name__ == '__main__':
        main.ArgvHandler()
    ftp_server.py

      创建一个conf文件,里面包含系统的配置信息,settings.py

      4.1.1.2 conf文件  

    IP="127.0.0.1"
    PORT=8089
    settings.py

      创建一个core文件,里面包含系统的核心代码,main.py和server.py

      4.1.1.3 core文件    

    import optparse
    #引入optparse模块:其作用是把用户输入的命令匹配成字典形式,参考示例1
    import socketserver
    #引入socketserver模块:其作用是创建连接对象,启动ftp服务端
    from conf import settings
    #引入settings模块:其作用是通过配置文件拿到IP地址和端口号
    from core import server
    #引入server模块:其作用是把主要的逻辑放置到server中,
    # 注意:由于main方法不是启动方法,启动方法在bin中,所以需要通过引用的方式实现
    class ArgvHandler():
        #功能1:用户输入命令-启动ftp_server
        def __init__(self):
            self.op = optparse.OptionParser()
            options, args = self.op.parse_args()
            self.verify_args(options, args)
    
        def verify_args(self,options, args):
            #命令分发,通过反射来实现
            cmd=args[0]
            if hasattr(self,cmd):
                fun=getattr(self,cmd)
                fun()
        def start(self):
            print(" the server is working...")
            #启动方法
            s=socketserver.ThreadingTCPServer((settings.IP,settings.PORT),server.ServerHandler)
            s.serve_forever()
    
    '''
    示例1:---开始
    self.op = optparse.OptionParser()
    self.op.add_option("-s", "--server", dest="Server")
    self.op.add_option("-p", "--port", dest="Port")
    options, args = self.op.parse_args()
    print(options)
    print(options.Server)
    print(args)
    示例1在Terminal中输入命令
    D:CodeFTPFTP_serverin> python ftp_server.py -s 127.0.0.1 -p 8089 abc
    示例1运行结果
    {'Server': '127.0.0.1', 'Port': '8089'}
    127.0.0.1
    ['abc']
    示例1--结束
    '''
    main.py
    import socketserver
    class ServerHandler(socketserver.BaseRequestHandler):
        #主要用于服务端的处理方法
        def handle(self):
            print("ok")
    server.py

      创建一个logger文件,主要用户记录日志

      4.1.1.4 logger文件  

        4.1.2 FTP_client

      里面先简单设置一个ftp_client.py的测试客户端  

    import socket
    sk=socket.socket()
    sk.connect(("127.0.0.1",8089))
    ftp_client.py

  • 相关阅读:
    一个matlab小程序:挑出沪市A股年报与一季度报在同一天发布的股票
    AWK
    matlab搜索路径
    从新浪财经上下载交易明细数据并统计每天的买卖笔数(shell 命令行)
    AWK截取字符串
    tar GNU
    工作效率上的错觉(转载)
    matlab双精度浮点数编码及区间覆盖(原创)
    DNS服务器设置(Ubuntu10.04)
    sed
  • 原文地址:https://www.cnblogs.com/YK2012/p/9802222.html
Copyright © 2011-2022 走看看