python socket,当缓冲区不够大时如何接收所有消息?

时间:2014-12-14 07:30:13

标签: python sockets

# addition_server.py

import socket

buf_size = 4
host = ''
port = 8000
server_addr = (host, port)


def get_msg(soc):
    msg = ''
    while True:
        temp = soc.recv(buf_size)
        if not temp:
            break
        msg += temp
    return msg

if __name__ == '__main__':
    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # socket.error: [Errno 98] Address already in use
    soc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    soc.bind(server_addr)
    soc.listen(0)

    runnnig = True
    while runnnig:
        client_soc, client_addr = soc.accept()
        print client_addr
        # socket.error: [Errno 104] Connection reset by peer
        message = client_soc.recv(buf_size)
        #message = get_msg(client_soc)
        if message == 'q':
            runnnig = False
        numbers = message.split(' ')
        numbers = filter(None, numbers)
        try:
            numbers = map(int, numbers)
            s = sum(numbers)
            numbers = map(str, numbers)
            answer = ' + '.join(numbers)
            answer = '%s = %s' % (answer, s)
        except Exception as e:
            print e
            answer = 'error'
        client_soc.sendall(answer)
        client_soc.close()
    soc.close()

# addition_client.py

import socket
from addition_server import get_msg
from addition_server import server_addr

buf_size = 1
runnnig = True
while runnnig:
    soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    soc.bind(('', 6060))  # without this, random port will be assigned
    soc.connect(server_addr)
    msg = raw_input('> ')
    if not msg:
        soc.close()
        break
    else:
        if msg == 'q':
            runnnig = False
    soc.sendall(msg)
    #reply = soc.recv(buf_size)
    # socket.error: [Errno 104] Connection reset by peer
    reply = get_msg(soc)
    print reply
    soc.close()

~/nuts/git/socket_learn/pairs$ python addition_client.py 
> 1 2
1 + 2 = 3
> 1 2 3
Traceback (most recent call last):
  File "addition_client.py", line 23, in <module>
    reply = get_msg(soc)
  File "/home/phy/nuts/git/socket_learn/pairs/addition_server.py", line 14, in get_msg
    temp = soc.recv(buf_size)
socket.error: [Errno 104] Connection reset by peer

服务器中的缓冲区大小故意很小,因此您可以看到上述错误。 但是get_msg(client_soc)方法在服务器中不起作用,我不知道为什么。

1 个答案:

答案 0 :(得分:2)

套接字流协议实现,并且没有隐式消息边界。

除非消息内容本身指定了消息,否则读者无法知道消息是否完整。电线上没有额外的边界。

当你调用recv并且缓冲区中没有数据时,调用将引发异常(非阻塞套接字)或者只是等待(阻塞套接字)。

sendall工具只是为了避免在发送缓冲区时编写循环,但当然没有办法实现recvall,因为无法知道消息何时完成。

您需要为协议添加消息边界;这可以是分隔消息或为每条消息添加消息大小前缀的换行符。通过这种方式,读者可以在开始处理之前知道消息何时完成。