V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
18870715400
V2EX  ›  Python

我又来了, 又是关于 socket 的

  •  
  •   18870715400 · 2020-06-16 22:53:49 +08:00 · 2871 次点击
    这是一个创建于 1417 天前的主题,其中的信息可能已经有所发展或是发生改变。

    附上代码:

    server 端

    from socketserver import BaseRequestHandler, ThreadingTCPServer
    
    
    class Handler(BaseRequestHandler):
    
        def setup(self) -> None:
            self.request.settimeout(1)
    
        def handle(self):
            while 1:
                try:
                    data = "这是主机端的信息"
                    self.request.sendall(data.encode("utf-8"))
                except BaseException as e:
                    print(e)
                    print("关闭连接:{}".format(self.client_address[0]))
                    break
    
    
    if __name__ == '__main__':
        host = ("localhost", 8000)
        server = ThreadingTCPServer(host, Handler)
        server.serve_forever()
    

    client 端

    import socket
    import time
    
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    host = ("localhost", 8000)
    
    client.connect(host)
    
    
    while 1:
        data = client.recv(2000)
        if len(data) <= 0:
            break
    
        print("从主机端接受信息:{}".format(data.decode()))
        # time.sleep(1)
    
    

    运行 client 的时候有的时候会报错,'utf-8' codec can't decode bytes in position

    但是如果在 server 端 self.request.sendall 发送英文的时候就不会报错, 个人估计是因为编码后的中文传输的时候 client 端接收的数据不够完整, 比如一个 编译后的 字节数据是 \xe5\x93\x88 但是接收的时候只有接收到 xe5\x9 导致 client 端解析的时候出错了, 大家有什么方法保证数据的完整性么

    第 1 条附言  ·  2020-06-18 00:10:34 +08:00

    已经解决了, 数据开头显示数据长度

    server端

    #! /usr/bin/env python
    # coding=utf-8
    from socketserver import BaseRequestHandler, ThreadingTCPServer
    
    
    class Handler(BaseRequestHandler):
    
        def setup(self) -> None:
            self.request.settimeout(1)
    
        def handle(self):
            while 1:
                try:
                    data = "这是主机端的信息"
                    length = len(data.encode())
                    length_string = "0" * (8 - len(str(length))) + str(length)
                    print(length_string)
                    self.request.sendall(length_string.encode() + data.encode())
                except BaseException as e:
                    print(e)
                    print("关闭连接:{}".format(self.client_address[0]))
                    break
    
    
    if __name__ == '__main__':
        host = ("localhost", 8000)
        server = ThreadingTCPServer(host, Handler)
        server.serve_forever()
    

    client端

    #! /usr/bin/env python
    # coding=utf-8
    import socket
    import time
    
    
    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
    host = ("localhost", 8000)
    
    client.connect(host)
    
    remainging = b""
    
    while 1:
        data = client.recv(2001)
        if len(data) <= 0:
            break
        data = remainging + data
    
        coursor = 0
        while coursor < len(data):
            size = int(data[coursor:8+coursor].decode())
            infos = data[8+coursor:8+coursor+size].decode()
            coursor = 8 + coursor + size
            print(infos)
            print(coursor, 111)
            if len(data) - coursor <= 8:
                break
            else:
                if coursor + int(data[coursor:coursor+8].decode()) + 8 > len(data):
                    break
    
        remainging = data[coursor:]
    
    
        time.sleep(1)
    
    15 条回复    2020-06-17 16:24:55 +08:00
    18870715400
        1
    18870715400  
    OP
       2020-06-16 22:58:49 +08:00
    还有, 关于 self.request.recv()的 函数怎么不阻塞,

    我在 Handler 中的 setup 函数中设置 self.request.settimeout(0) 之后会报一个 参考的对象类型不支持尝试的操作错误, 应该怎么解决呢
    est
        2
    est  
       2020-06-16 23:47:00 +08:00
    还是去学一下 python 基础吧。
    CEBBCAT
        3
    CEBBCAT  
       2020-06-17 00:04:50 +08:00 via Android
    你还需要学习 TCP 基础,再出错也不至于传半个字节给 Python 呐……

    另外你这是面向论坛工作吗?
    Caratpine
        4
    Caratpine  
       2020-06-17 00:07:27 +08:00
    学习 TCP +1,TCP 是流传输。
    一种办法是在传送消息的时候把消息长度作为头信息也传给客户端。
    wy
        5
    wy  
       2020-06-17 00:59:00 +08:00 via Android
    可以参考一下 HTTP 中的 chunk 编码方式。简单来说就是先发送一个长度,然后再发对应长度的数据。这样客户端就去可以判断数据是否完整了。
    wangyzj
        6
    wangyzj  
       2020-06-17 01:38:04 +08:00
    data = client.recv(24)
    这样就不会报错了
    哈哈哈
    yeept
        7
    yeept  
       2020-06-17 08:32:03 +08:00
    Socket 一定要注意处理数据边界,可参考 #5 方式
    18870715400
        8
    18870715400  
    OP
       2020-06-17 09:05:07 +08:00
    好的,
    mingl0280
        9
    mingl0280  
       2020-06-17 10:11:00 +08:00
    TCP 基础常识:TCP 是一个字节流协议,客户端或服务器收到的字节流有多长没人知道.TCP 只保证字节流的顺序是正确的.这也是为什么 TCP 需要一个上层的协议来保证消息完整性的原因.
    cweijan
        10
    cweijan  
       2020-06-17 11:18:25 +08:00
    楼上正解
    hankai17
        11
    hankai17  
       2020-06-17 13:53:43 +08:00
    实现一套 http 用来收发
    Chenamy2017
        12
    Chenamy2017  
       2020-06-17 14:13:14 +08:00
    1. 学习下 TCP 数据流处理吧
    2. 调试时你可以将收到的数据打印出来(用十六进制)看看你都收到了些什么数据,看到数据你就明明白白的了
    gesse
        13
    gesse  
       2020-06-17 15:57:14 +08:00
    client.recv(2000)

    你这个把 utf-8 编码截断了。

    >>> len('这是主机端的信息'.encode('utf-8'))
    24

    你把 2000 改成 24 的倍数就可以了。
    18870715400
        14
    18870715400  
    OP
       2020-06-17 16:16:34 +08:00
    @gesse 你的这个方法的确有用, 但是如果服务端发送的数据是不定长的呢?不是整倍数
    18870715400
        15
    18870715400  
    OP
       2020-06-17 16:24:55 +08:00
    我明白了各位所说的, 我的原意是 比如说 哈 的编码是 b'\xe5\x93\x88' 但是由于 recv 中 buff_size 限制原因导致只取到了前两个字节 b'\xe5\x93' 所以 decode 的时候会报错, 我现在知道 \xe5 是一个完整的字节, 所以问的时候才会犯上面的错误, 现在是需要如何将完整的数据拼接起来
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1167 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 17:41 · PVG 01:41 · LAX 10:41 · JFK 13:41
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.