# 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)方法在服务器中不起作用,我不知道为什么。
答案 0 :(得分:2)
套接字流协议实现流,并且没有隐式消息边界。
除非消息内容本身指定了消息,否则读者无法知道消息是否完整。电线上没有额外的边界。
当你调用recv
并且缓冲区中没有数据时,调用将引发异常(非阻塞套接字)或者只是等待(阻塞套接字)。
sendall
工具只是为了避免在发送缓冲区时编写循环,但当然没有办法实现recvall
,因为无法知道消息何时完成。
您需要为协议添加消息边界;这可以是分隔消息或为每条消息添加消息大小前缀的换行符。通过这种方式,读者可以在开始处理之前知道消息何时完成。