私はインターネットでこの特定の問題についてたくさん見たり読んだりしました。主に学習目的でpython)のソケットを使用して簡単なチャットサーバーとクライアントを作成しています。
ここで問題が発生しました。
これが私のサーバーコードです:
___author__ = 'pchakraverti'
import socket
import select
import sys
class NickSocketMap(object):
count = 0
def __init__(self, nick, client_socket):
self.nick = nick
self.client_socket = client_socket
NickSocketMap.count += 1
@staticmethod
def display_count():
print "Total number of clients is %d" % NickSocketMap.count
Host = ""
port = 7575
socket_list = []
nick_list = []
cnt = 0
recv_buffer = 1024
def register_nick(nick, client_socket):
obj = NickSocketMap(nick, client_socket)
nick_list.append(obj)
def process_request(request_string, client_socket):
parts = request_string.split("|")
if parts[0] == "set_nick":
register_nick(parts[1], client_socket)
client_socket.send("nick_set")
Elif parts[0] == "transmit_msg":
broadcast_message(parts[1], parts[2])
return 1
def broadcast_message(message, client_nick):
for s in nick_list:
if s.nick == client_nick:
try:
s.client_socket.send(message)
except socket.errno, ex:
print ex
break
def run_server():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.bind((Host, port))
except socket.errno, ex:
print ex
sys.exit(-1)
sock.listen(10)
# add the parent socket in the list
socket_list.append(sock)
# keep the server alive
while True:
try:
read_ready, write_ready, in_error = select.select(socket_list, [], [], 0)
except select.error, ex:
print ex
continue
for s in read_ready:
# check if s is the parent socket
if s == sock:
# accept new connection and append to list
try:
con, addr = s.accept()
if con not in socket_list:
socket_list.append(con)
except socket.errno, ex:
print ex
else:
try:
# receive packet from connected client
packet = s.recv(recv_buffer)
if not packet:
socket_list.remove(s)
read_ready.remove(s)
for n in nick_list:
if n.client_socket == s:
nick_list.remove(n)
break
break
print packet
except socket.errno, ex:
print ex
continue
process_request(packet, s)
sock.close()
if __name__ == "__main__":
run_server()
_
これが私のクライアントコードです:
___author__ = 'pchakraverti'
import socket
nick = ""
Host = "192.168.0.167"
port = 7575
sock = ""
def welcome():
print "Welecome to SecuChat!"
print "---------------------"
def init():
nick = raw_input("Enter your chat nickname : ")
print nick
global sock
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect((Host, port))
except socket.errno, ex:
print ex
sock.send("set_nick|"+nick)
#sock.close()
if __name__ == "__main__":
welcome()
init()
_
クライアントコードで、sock.close()
を実行しないと、サーバーで例外が発生します。
_Traceback (most recent call last):
File "server.py", line 102, in <module>
run_server()
File "server.py", line 84, in run_server
packet = s.recv(recv_buffer)
socket.error: [Errno 104] Connection reset by peer
_
ただし、その行を追加しても問題は発生しません。
今私は2つの質問があります:
i)server.pyで例外を処理しましたが、なぜこの例外が処理されないのですか、またなぜコードがクラッシュするのですか?サーバーをより堅牢にするにはどうすればよいですか?また、何が欠けていますか?
ii)クライアントのsock.close()
行に関連して、このクラッシュと例外の背後にあるロジックは何ですか?
i)try-exceptブロックは例外をキャッチしません。
except
の最初の引数は、キャッチする例外のタイプである必要があります。 _socket.errno
_は例外クラスではなく、モジュールです。 _socket.error
_をキャッチする必要があります:
_ except socket.error, ex:
print ex
_
コールスタックのどこかで処理されない例外は、except
に到達するまで外部に伝播するため、コードが「クラッシュ」します。ハンドラーがない場合、プログラムは終了します。
ii)クライアントが接続を閉じずに終了すると、RST
パケットがOSのTCP/IPスタックによって送信されます。これは、さようならを言わずに電話を切るのとほぼ同じです。 Pythonは、これを「ピアによって接続がリセットされました」というテキストで例外に変換します。これは、read()
Pythonあなたは何かを受け取ることを期待していて、接続が突然切断されたとき、Pythonは例外を発生させることによって、これを通知します。