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
woshichuanqilz
V2EX  ›  Python

为什么这个 client 端的 socket 收不到 server 发来的信息?

  •  
  •   woshichuanqilz · 2018-02-23 09:20:47 +08:00 · 4092 次点击
    这是一个创建于 2472 天前的主题,其中的信息可能已经有所发展或是发生改变。

    下面是代码, server 端会在 recv 上挂住 这个是为什么?

    server:

    # -*- coding: UTF-8 -*-
    
    # 导入库
    import socket, threading, os, uuid, sys
    
    SIZE = 1024 * 1024 * 5
    filename = str(uuid.uuid4()) + '.jpg'
    
    # 检查当前目录下是否有等下要命名的图片,有的话删除之
    def checkFile():
        list = os.listdir('.')
        for iterm in list:
            if iterm == filename:
                os.remove(iterm)
                print('remove')
            else:
                pass
    
    # 接受数据线程
    def tcplink(sock, addr):
    # def tcplink():
        print('Accept new connection from %s:%s...' % addr)
        # sock.send(b'Welcome from server!')
        print('receiving, please wait for a second ...')
        while True:
            try:
                data = sock.recv(SIZE)
                if not data :
                    print('reach the end of file')
                    break
                elif data == 'begin to send':
                    print('create file')
                    checkFile()
                    with open(filename, 'wb') as f:
                        pass
                else:
                    with open(filename, 'ab') as f:
                        f.write(data)
            except:
                print("Unexpected error:", sys.exc_info()[0])
                break
        print('msg send')
        sock.send(b'Welcome from server!')
        sock.close()
        print('receive finished')
        print('Connection from %s:%s closed.' % addr)
    
    
    # 创建一个 socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 监听端口(这里的 ip 要在不同的情况下更改)
    s.bind(('127.0.0.1', 9999))
    # 每次只允许一个客户端接入
    s.listen(2)
    print('Waiting for connection...')
    while True:
        # 建立一个线程用来监听收到的数据
        sock, addr = s.accept()
        t = threading.Thread(target = tcplink, args = (sock, addr))
        # 线程运行
        t.start()
    
    

    client:

    # -*- coding: UTF-8 -*-
    import socket
    
    SIZE = 1024 * 1024 * 5
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 建立连接:
    s.connect(('127.0.0.1', 9999))
    
    # 接收欢迎消息:
    with open('./image.png', 'rb') as f:
       data = f.read()
       s.sendall(data)
    
    print('sended !')
    data = s.recv(SIZE)
    # print(data)
    
    s.close()
    print('connection closed')
    
    
    第 1 条附言  ·  2018-02-23 11:55:21 +08:00

    在filewrite后面加上了break之后没问题了,

    现在的listen(2)改成了(1),

    就是有概率出现了远程主机强迫关闭的问题, 这个如何解决?

    server 端close的地方只有这里这里, 那client端的recv为什么会在收到信息之前socket的断掉了呢?

        print('msg sendall')
        sock.sendall(b'Welcome from server!')
        sock.close()
    
    

    20180223115206

    10 条回复    2018-02-23 13:39:00 +08:00
    opengps
        1
    opengps  
       2018-02-23 09:36:32 +08:00
    可惜我不懂你的语言,回答不规范,我看着问题像是 while True 内部那里,没有启用单独的线程处理啊,这样的话,你服务端没法接收并发消息的
    heimeil
        2
    heimeil  
       2018-02-23 09:41:14 +08:00
    不知道是不是没收到 welcome,你仔细看看 server 在 send welcome 之前就 while True 了
    coderwang
        3
    coderwang  
       2018-02-23 09:49:21 +08:00
    f.write(data) 之后 break
    j0hnj
        4
    j0hnj  
       2018-02-23 09:55:06 +08:00 via iPhone
    客户端 sendall 之后就把 socket shutdown 吧,这样服务端的 recv 才会收到 EOF 返回,不然就卡住了。或者也可以像 HTTP 一样加一个 content-length 字段
    j0hnj
        5
    j0hnj  
       2018-02-23 10:18:12 +08:00 via iPhone
    具体一下就是客户端在 sendall 之后应该 s.shutdown(socket.SHUT_WR) 关闭自己的写端
    linyinma
        6
    linyinma  
       2018-02-23 10:23:07 +08:00
    这边有几个问题:
    ( 1 )首先检查./image.png 文件是否存在(文件大小,是否是空文件);
    ( 2 )
    data = sock.recv(SIZE)
    if not data :
    print('reach the end of file')
    这不是文件发送完的意思,是代表对方关闭了 socket,你不能这样写;

    ( 3 ) TCP 流你无法确定应用层报文是否发送完整,你需要定义一套应用层协议,比如定义头两个字节表示文件长度,服务端先读两个字节判断应用层报文大小,然后读完整个报文~~
    woshichuanqilz
        7
    woshichuanqilz  
    OP
       2018-02-23 11:30:37 +08:00
    @coderwang 你好 确实是 break 哪里的问题加上就好了, 能简单解释下为什么吗? 谢谢~
    coderwang
        8
    coderwang  
       2018-02-23 11:59:49 +08:00
    @woshichuanqilz 不 break 循环不会中断,一直卡在 receive
    woshichuanqilz
        9
    woshichuanqilz  
    OP
       2018-02-23 13:02:50 +08:00
    @j0hnj shutdown 之后后面的 server 要发的东西就发不出去了。
    j0hnj
        10
    j0hnj  
       2018-02-23 13:39:00 +08:00 via iPhone
    @woshichuanqilz #9 TCP 是全双工的,客户端关闭写端,但是仍然可以读取服务端的响应,我这边测试是没问题的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2937 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:50 · PVG 10:50 · LAX 18:50 · JFK 21:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.