2

私は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 経由で接続すると、サーバーは 1 文字を読み取り、次の文字をスキップします。たとえば、telnet で Hello と入力すると、サーバーは H lo を読み取ります。何か助けてください?! :)

4

1 に答える 1

4

recv を 2 回呼び出します。

初め:

msg=s.recv(100)

次に、それが「終了」でない場合は、別のメッセージを読んでブロードキャストします。

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

したがって、元のメッセージは失われます。

クライアントとして telnet を使用しているため、一度に 1 つの文字を取得するため、他のすべての文字が表示されます。たとえば、代わりに nc を使用すると、異なる結果が得られますが、他のすべての読み取りが破棄されるという基本的な問題は同じです。

ここには他にもいくつかの問題があります。

  • クライアントが終了する前に「quit」を送信することを期待しています。recv からの EOF またはエラーを処理するか、r と同様に x でソケットを渡す必要があります。
  • 「quit」は常に単一のメッセージに表示され、メッセージ全体がそれ自体に表示されると想定しています。これは、TCP では妥当な仮定ではありません。「q」、「u」、「i」、「t」の 4 つの 1 バイト読み取りを取得するか、「OK、さようなら\nquit\n」の大きな読み取りを取得する場合がありますが、どちらも一致しません。 .
  • "Client left" および "Client Joined" メッセージは、文字列ではなくタプルであり、形式が異なるため、('Client Joined', "('127.0.0.1', 56564)") ( 「クライアントは去りました」、(「127.0.0.1」、56564))。
  • メッセージ間に改行を送信するためにクライアントに依存しています。まず、前述のように、たとえそうであったとしても、完全なメッセージまたは個別のメッセージが得られるという保証はありません。第二に、「システム」メッセージには改行がありません。

「quit」を 1 つのメッセージだけにする必要があることと、クライアントが改行を送信することに依存することを除いて、ほとんどの問題を修正するサンプルの修正版を次に示します。

#!/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]

しかし、まだ改行の問題があります。user1 がログインして「abc\n」と入力し、user2 がログインして「def\n」と入力するとします。「abClient Joined: 127.0.0.1:56881\ndec\nf\n」のようなメッセージが表示される場合があります。

行ベースのプロトコルが必要な場合は、読み取りごとではなく行ごとにエコーを行うようにコードを書き直す必要があります。

于 2012-07-09T18:58:56.273 に答える