• python 第七天


    1、socket就是将下边的TCP/IP协议进行封装,留出来的接口用户通信

    1.1、Socket Families

    socket.AF_UNIX unix本机进程间通信

    socket.AF_INET IPV4

    socket.AF_INET6 IPV6

    1.2、Socket Types

    socket.SOCK_STREAM   #for tcp

    socket.SOCK_DGRAM   #for udp

    2、Socket 参数

    2.1、socket.socket(family=AF_INETtype=SOCK_STREAMproto=0fileno=None)

    声明socket类型,同时生成socket链接对象

    2.2、s.bind(address)

    s.bind(address) 将套接字绑定到地址

    2.3、s.listen(backlog)

    开始监听传入连接

    2.4、sk.setblocking(bool)

    是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。

    2.5、sk.accept()

    接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。
    2.6、sk.connect(address)

    连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误

    2.7、sk.close()

    关闭套接字

    2.8、sk.recv(bufsize[,flag])

    接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

    2.9、sk.send(string[,flag])

    将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。

    2.10、sk.sendall(string[,flag])

    将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。

    2.11、sk.settimeout(timeout)

    设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )

    2.12、sk.getpeername()

    返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)

    3、基本Socket实例

    socket_server.py:

    import socket
    server = socket.socket()
    server.bind(('localhost',9999)) #绑定要监听的接口
    server.listen() #监听
    print("我要开始等电话了")
    while True:
      conn, addr = server.accept() # 接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来
      print("电话来了")
    while True:
        data = conn.recv(1024) #等着收数据
        #为了防止收到是数据是Ctrl + C,是Ctrl + C的话会出现异常,其实就是收到的数据一直是空,判断如果是,就重新监听
        if not data:
          print("lost...")
          break
        conn.send(data.upper())
    server.close()
    socket_client.py:
    import socket
    client = socket.socket() #声明socket类型,同时生成socket链接对象
    client.connect(('localhost',9999))
    while True:
      msg = input(">>:").strip() #不能Send空
      if len(msg) == 0:
        continue
      client.send(msg.encode("utf-8"))
        """在 Python3 中,bytes 和 str 的互相转换方式是
    str.encode('utf-8') 转成byte
    bytes.decode('utf-8') 转成str"""

      data = client.recv(1024)
      print(data.decode('utf-8')) #decode默认就解成unicode
    client.close()
        

    4、通过socket实现简单得SSH
    socket ssh server:
    server.bind('localhost',9999)
    server .listen()
    while True:
      conn,addr = server.accept()
      print("new conn",addr)
      whilt True:
        print("等待客户指令")
        data = conn.recv(1024)
        if not data:
          print("客户端已断开")
          break
        print("执行指令:"data)
        cmd_res = os.popen(data.decode()).read #接收字符串的命令,数目相关执行结果
        conn.send(cmd_res.encode('utf-8')) #如果服务端没有任何执行结果,是不会客户端发送数据的
        print('send done') 
    socket ssh client:
    import socket
    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)
      print("命令结果大小:",cmd_res_size.decode())

    client.close()

    以上会出现,加入服务端对输入的命令无响应,客户端就会进入等待收命令的假死状态,而且由于接收缓存区的问题,会出现粘包的问题。
    解决方法粘包的方法,就是先发数据的大小,客户端收到数据大小之后,进行比较,一直不断的接受,直到收到的完整的数据

    5、socket优化版import socket
    socket ssh server:
    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.encode()))
    if len(cmd_res) == 0:
    cmd_res = "cmd has no output..."
    conn.send(str(len(cmd_res.encode())).encode('utf-8')) #先发大小给客户端
    aaa = conn.recv(1024) #等待确认
    print(aaa.decode())
    conn.send(cmd_res.encode('utf-8')) #客户端没有收到数据,因为没有数据,服务器是不会发的
    print("send done")

    server.close()

    socket ssh client:
    client = socket.socket()
    client.connect(('localhost',9999))

    while True:
    cmd = input(">>:").strip()
    # print(cmd)
    if len(cmd) == 0:
    continue
    client.send(cmd.encode('utf-8'))
    cmd_res_size = client.recv(1024) #收到要传数据的大小
    client.send(b"len is ok") #为了防止和下边即将收到的数据粘包,对收到的数据进行回应,此种方法只能针对小于size大小的数据包
    print("命令结果大小:",cmd_res_size.decode())
    received_size = 0
    total_size = int(cmd_res_size.decode())
    received_data = b''
    while received_size < total_size: #为了防止粘包,对收到的数据进行处理
    if total_size - received_size > 1024: #只要未收到的大于1024就赋值1024,要不然赋值剩余的收取的数据
    size = 1024

    else:
    size = total_size - received_size
    print("last receive:", size)
    data = client.recv(size)
    received_size += len(data)
    received_data += data

    else:
    print("cmd res recevie done...",received_size)
    print(received_data.decode())
    #后边就可以继续加要收取的数据了,这样子和上边的数据就不会粘包了

    client.close()


    6、socket简单的ftp服务器
    import socket,os,hashlib
    server = socket.socket()
    server.bind(('localhost',9999))
    server.listen()
    while True:
      conn,addr = server.accpect()
      print("new conn:",addr)
      while True:
        print("等待指令”)
        data = conn.recv(1024)
        if not data:
          print("客户端已经断开")
          break
        cmd,filename = data.decode().split() #默认已空格进行分割
        print(filename)
        if os.path.isfile(filename):
          f = open(filename,'rb')
          m = hashlib.md5()
          #stat 系统调用时用来返回相关文件的系统状态信息,后边很多属性,这次只用了st_size的属性
          file_size = os.stat(filename).st_size #文件的大小
          conn.send(str(file_size).encode()) #send file size
          conn.recv(1024) #wait for ack
          for line in f: #文件都是可以按照行读取的,这种不是一次性读取,这种方式是迭代器
            conn.send(line)
            m.update(line)
          f.close()
          conn.send(m.hexdigest().encode())
        print(‘send done’)
    server.close()

        
    ftp client:
     import socket,hashlib
    client = socket.socket()
    client.connect(('localhost',9999))

    while True:
    cmd = input(">>:").strip()
    if len(cmd) == 0:continue
    # python startswith() 方法用于检查字符串是否是以指定子字符串开头,如果是则返回 True,否则返回 False
    if cmd.startswith("get"):
    client.send(cmd.encode())
    server_response = client.recv(1024)
    print("server respone:",server_response)
    client.send(b"ready to recv file")
    m = hashlib.md5()
    file_total_size = int(server_response.decode())
    received_size = 0
    filename = cmd.split()[1]
    print(filename)
    f = open(filename + ".new","wb")
    while received_size < file_total_size:
    if file_total_size - received_size > 1024:
    size = 1024
    else:
    size = file_total_size - received_size
    print("last receive:",size)
    data = client.recv(size)
    received_size += len(data)
    m.update(data)
    f.write(data)
    else:
    print("file recv done",received_size,file_total_size)
    new_file_md5 = m.hexdigest()
    f.close()
    server_file_md5 = client.recv(1024)
    print("server file md5:",server_file_md5.decode())
    print("client file md5:",new_file_md5)
    client.close()


       
    7、socket 用类来写
    1、导入socketserver 模块
    2. 继承socketserver.BaseRequestHandler类
    3.重写handle方法,在handle方法中实现所有的socket内容     

    4.实例化
    socket server:

    import socketserver
    class MyTCPHandler(socketserver.BaseRequestHandler):
      def handle(self):
        while True:
          try:
            self.data = self.request.recv(1024).strip() #request方法就是接收或者发送数据
            if not self.data:
              print("lost.....")
            else:
            # str.format() 其实是将括号中的文字放到前面
               print("{} write:".format(self.client_address[0])) #这些client_address都是继承父类的属性
                        print(self.client_address)
    print(self.data)
    self.request.send(self.data.upper())
    except Exception as e:
    print("err",e)
    break
    if __name__ == "__main__":
    HOST, PORT = "localhost", 9999
    server = socketserver.ThreadingTCPServer((HOST, PORT),MyTCPHandler)
    #执行 BaseServer.server_forever 方法,While 循环一直监听是否有客户端请求到达 ...
    server.serve_forever()
    socket client:
    import socket,sys
    HOST, PORT = 'localhost',9999
    #sys.argv[1:] 就是提取传入的参数1包括后面的变量
    # data = " ".join(sys.argv[1:])
    # Create a socket (SOCK_STREAM means a TCP socket)
    sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #这是默认参数,可以直接写成 socket.socket()
    sock.connect((HOST,PORT))
    while True:
    data = input(">>:").strip()
    sock.sendall(data.encode('utf-8'))
    received = str(sock.recv(1024).decode())
    print("Sent: {}".format(data))
    print("Received: {}".format(received))
    sock.close()
     
  • 相关阅读:
    【hibernate】自定义转换器
    【hibernate】存储图片
    【hibernate】映射可嵌入式组件
    【hibernate】应用程序级别的视图
    adb shell模拟点击事件(input tap)
    Android UIAutomator 定位
    adb devices连接不上设备
    获取元素属性get_attribute
    wait_activity
    webview定位 & native和webview切换
  • 原文地址:https://www.cnblogs.com/qianyuyu/p/10120046.html
Copyright © 2020-2023  润新知