• python3 socket


    python 套接字编程的大致流程如下:

    server端:

    client端 :

    在此基础上我们建立一个最基本的服务端,客户端(也就是所谓的cs模型)

    server:

    #!/usr/bin/env python
    #coding:utf-8
    #Created by Andy @ 2017/9/16
    
    
    import socket
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(("127.0.0.1", 8081))
    server.listen(5)
    
    conn, client_addr = server.accept()
    msg = conn.recv(1024)
    
    print(msg)
    conn.close()
    server.close()
    

     client

    #!/usr/bin/env python
    #coding:utf-8
    #Created by Andy @ 2017/9/16
    
    
    import socket
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(("127.0.0.1", 8081))
    
    client.send("hello, server".encode("utf-8"))
    client.close()
    

     这大概是最简单的cs模型了,事实上这样只完成了一次从客户端向服务端发送了一条消息,然后就关闭了连接。在实际情况中,服务端应该始终保持链接,通信也就是

    上图中的链接循环,通信循环。

    我们对上面的代码进行修改:

    server:

    #!/usr/bin/env python
    #coding:utf-8
    #Created by Andy @ 2017/9/16
    
    
    import socket
    
    BUFF_SIZE = 1024
    IP_PORT = ("127.0.0.1", 8081)
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(IP_PORT)
    server.listen(5)
    
    while True:
        conn, client_addr = server.accept()
    
        while True:
            msg = conn.recv(BUFF_SIZE)
            if not msg:
                break
            else:
                conn.send(msg)
                msg = msg.decode("utf-8")
                print(client_addr, msg)
    
        conn.close()
    server.close()
    

     client:

    #!/usr/bin/env python
    #coding:utf-8
    #Created by Andy @ 2017/9/16
    
    
    import socket
    
    BUFF_SIZE = 1024
    IP_PORT = ("127.0.0.1", 8081)
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(IP_PORT)
    
    while True:
        msg = input(">>:").strip().encode("utf-8")
        if not msg:
            break
        else:
            client.send(msg)
    
        response = client.recv(BUFF_SIZE)
        if response:
            print(response.decode("utf-8"))
    
    client.close()
    

     这样就实现了简单的链接循环,通信循环。

    但还有一个问题,就是可能出现粘包,

    1.由于tcp的机制,假如我一次只发送了5bytes的数据,它可能只是缓存起来了,并没有直接发送,

    等到我再次发送了若干数据(如100bytes)后它将这些数据一起发送出去,这样数据在客户端已经粘包。

    2.同样,在服务端解码时也可能出现,也可能出现粘包现象,即将前后多个包一次解码,数据在服务端出现粘包。

    那么,要怎么解决呢?

    可以看到问题就出在解包时不知道某个包的具体长度是多少,如果我们知道某个包的长度,只需要按照这个包的长度

    去解包,即使它粘包了,我们仍然能解出正确的数据来。

      

    那么就需要我们来定制报头,来告知解码的一方这个包的长度:

    下面以模拟ssh来做这个例子,

    我们约定报头的长度为四个字节。

    server:

    #!/usr/bin/env python
    #coding:utf-8
    #Created by Andy @ 2017/9/16
    
    
    import socket,json, struct, subprocess
    
    BUFF_SIZE = 1024
    IP_PORT = ("127.0.0.1", 8081)
    
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)# 重用端口
    server.bind(IP_PORT)
    server.listen(5)# 设置可以接受的连接数量
    
    while True:# 外层循环为链接循环
        conn, client_addr = server.accept()
    
        while True:# 内层循环为通信循环
            msg = conn.recv(BUFF_SIZE)
            if not msg:
                break
            pipes = subprocess.Popen(msg.decode("utf-8"),
                                     shell=True,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE
                                     )
    
            error = pipes.stderr.read()
            if error:
                print("Error:",error)
                response_msg = error
            else:
                response_msg = pipes.stdout.read()
    
            header = {'data_size':len(response_msg)}# 数据长度
            header_json = json.dumps(header)#序列化
            header_json_byte = bytes(header_json,encoding="utf-8")
    
            conn.send(struct.pack('i',len(header_json_byte)))
            #先发送报头长度,仅包含数据长度, 这里的i指int类型
            conn.send(header_json_byte)# 再发送报头
            conn.sendall(response_msg)# 正式的信息
            print("Request from:",client_addr, "Command:",msg)
    
        conn.close()
    server.close()
    

     client:

    #!/usr/bin/env python
    #coding:utf-8
    #Created by Andy @ 2017/9/16
    
    
    import socket, json, struct
    
    BUFF_SIZE = 1024
    IP_PORT = ("127.0.0.1", 8081)
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client.connect(IP_PORT)
    
    while True:
        msg = input(">>:").strip().encode("utf-8")
        if not msg:
            break
    
        client.send(msg)
    
        header = client.recv(4)
        print("Header:",struct.unpack("i", header))
        header_length = struct.unpack('i', header)[0]
        print("Header_length:", header_length)
        header_json = json.loads(client.recv(header_length).decode("utf-8"))
        data_size = header_json['data_size']
        print("Data_size:",data_size)
    
        recv_size = 0
        recv_data = b''
    
        while recv_size < data_size:
            recv_data += client.recv(BUFF_SIZE)
            recv_size += len(recv_data)
    
        print(recv_data.decode("gbk"))
    
    client.close()
    

     

     大致流程是这样的

    事实上,上面的例子只完成了一个客户端与服务器进行通信的功能,并没有实现如

    server端中写的server.listen(5),同时与5个客户端通信,要看如何实现可以参考:

    python3 进程

  • 相关阅读:
    Local File Manage in JavaScript Using FileSystemObject
    How to Register COM in VS
    Permission Error When Building C++ in VS2010
    Upload and Download File using Java
    JavaScript Interactive with ActiveX Control
    一个完整的Installshield安装程序实例
    一个.NET(C#)的双键字典类
    C#实现内存中字符串或byte[]的加解密
    判断请求是否来自 AJAX
    Reflector 7.3.018
  • 原文地址:https://www.cnblogs.com/Andy963/p/7532038.html
Copyright © 2020-2023  润新知