繁体   English   中英

Python套接字错误-recv()函数

[英]Python socket error - recv() function

我一直在尝试用Python编写一个简单的聊天服务器,我的代码如下:

import socket
import select

port = 11222
serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1024)
serverSocket.bind(('',port))
serverSocket.listen(5)

sockets=[serverSocket]
print 'Server is started on port' , port,'\n'

def acceptConn():
    newsock, addr = serverSocket.accept()
    sockets.append(newsock)
    newsock.send('You are now connected to the chat server\n')
    msg = 'Client joined',addr.__str__(),
    broadcast(msg, newsock)

def broadcast(msg, sourceSocket):
    for s in sockets:
        if (s != serverSocket and s != sourceSocket):
            s.send(msg)
    print msg,


while True:
    (sread, swrite, sexec)=select.select(sockets,[],[])
    for s in sread:
        if s == serverSocket:
            acceptConn()
        else:
            msg=s.recv(100) 
            if msg.rstrip() == "quit":
                host,port=socket.getpeername()
                msg = 'Client left' , (host,port)
                broadcast(msg,s)
                s.close()
                sockets.remove(s)
                del s
            else:
                host,port=s.getpeername()
                msg = s.recv(1024)
                broadcast(msg,s)
                continue

运行服务器并通过telnet连接后,服务器读取单个字符并跳过下一个字符。 例如,如果我在telnet中键入Hello,则服务器读取H10。 有什么帮助吗?! :)

您两次调用recv。

第一:

msg=s.recv(100)

然后,如果不是“退出”,则您阅读并广播了另一条消息:

msg = s.recv(1024)
broadcast(msg,s)

因此,原始消息丢失了。

因为您使用telnet作为客户端,所以一次只能获得一个字符,因此您可以看到其他所有字符。 如果使用nc代替,则会得到不同的结果,但是其他所有读操作都将被丢弃,这是相同的基本问题。

这里还有其他一些问题:

  • 您期望客户端在退出之前发送“退出”消息–您应该处理来自recv的EOF或错误,并且/或者在x和r中传递套接字。
  • 您假设“退出”将始终出现在单个消息中,而整个消息全部出现在自身中。 对于TCP,这不是一个合理的假设。 您可能会读取“ q”,“ u”,“ i”和“ t”的四个1个字节,或者可能会大读“ OK,再见,每个人\\ nquit \\ n”,这两个都不匹配。
  • “已离开客户”和“已加入客户”消息是元组,而不是字符串,并且它们的格式不同,因此您将看到('Clientjoind',“(''127.0.0.1',56564)”)( '客户离开'(('127.0.0.1',56564))。
  • 您依靠客户端在他们的消息之间发送换行符。 首先,如上所述,即使他们做到了,也无法保证您会收到完整/离散的消息。 其次,您的“系统”消息没有换行符。

这是示例的修改后的版本,它解决了大多数问题,除了要求“退出”仅包含在一条消息中并依靠客户端发送换行符之外:

#!/usr/bin/python

import socket
import select
import sys

port = 11222
serverSocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1024)
serverSocket.bind(('',port))
serverSocket.listen(5)

sockets=[serverSocket]
print 'Server is started on port' , port,'\n'

def acceptConn():
    newsock, addr = serverSocket.accept()
    sockets.append(newsock)
    newsock.send('You are now connected to the chat server\n')
    msg = 'Client joined: %s:%d\n' % addr
    broadcast(msg, newsock)

def broadcast(msg, sourceSocket):
    for s in sockets:
        if (s != serverSocket and s != sourceSocket):
            s.send(msg)
    sys.stdout.write(msg)
    sys.stdout.flush()


while True:
    (sread, swrite, sexec)=select.select(sockets,[],[])
    for s in sread:
        if s == serverSocket:
            acceptConn()
        else:
            msg=s.recv(100)
            if not msg or msg.rstrip() == "quit":
                host,port=s.getpeername()
                msg = 'Client left: %s:%d\n' % (host,port)
                broadcast(msg,s)
                s.close()
                sockets.remove(s)
                del s
            else:
                host,port=s.getpeername()
                broadcast(msg,s)
                continue

要解决“退出”问题,您将必须为每个客户端保留一个缓冲区,并执行以下操作:

buffers[s] += msg
if '\nquit\n' in buffers[s]:
   # do quit stuff
lines = buffers[s].split('\n')[-1]
buffers[s] = ('\n' if len(lines) > 1 else '') + lines[-1]

但是您仍然遇到换行问题。 假设用户1登录并键入“ abc \\ n”,而用户2登录并键入“ def \\ n”; 您可能会得到类似“ abClient加入:127.0.0.1:56881\\ndec\\nf\\n”的信息。

如果需要基于行的协议,则必须重写代码以逐行而不是逐读地执行回显。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM