【pythonネットワークプログラミング】マルチスレッドによるマルチユーザフルデュプレクスチャットの実現
3688 ワード
前の文章では,1対1の非同期通信を実現し,文章の終わりに多対多通信の構想を与えた.
と言った以上、やってみましょう.今回はマルチスレッドで実現して、ちょうど手を練習しています~
まず考えてみましょう.
サーバを中継局として情報を処理し,クライアントとインタラクティブになる一方でメッセージ転送を行う.
大体の考え方が確定したら、いくつかの通信規則を確定する必要があります.
1. クライアントがサーバと接続を確立した後、ユーザー名を入力してログインする必要があります.ユーザー名がすでに存在する場合、reuseをユーザーにフィードバックし、ユーザーはエラー情報を出力し、終了します.
2. ユーザーが正しいユーザー名を入力すると、通信ができます.通信オブジェクトが選択されていない場合、サーバは情報をフィードバックし、ユーザーに通信オブジェクトの選択を要求します.
3. 通信オブジェクトを選択する方法は、to:usernameを入力し、選択したオブジェクトが存在しない場合は、エラー情報をフィードバックし、再入力します.
4.通信対象が正しく選択されると、双方は接続を確立し、サーバ中継情報により通信する
5.通信中に「quit」が送信されると、メッセージを送信するスレッドが終了し、そのユーザがログインする準備ができていることをサーバに指示し、サーバがそのユーザを削除した後、メッセージをユーザにフィードバックし、ユーザがメッセージを受信するスレッドを終了して終了する
6.AがCと通信中である場合、BがAに情報を送信すると、Aの通信ウィンドウはBとの通信ウィンドウとなり、すなわちBメッセージを受信すると、AからのメッセージはCではなく、Bにデフォルトで送信される
もちろん、本プログラムには、通信双方においてAが終了した場合でも、他方のBの通信リストにAが残っている場合でも、Bが登録されたBにメッセージを送信するとエラーが発生するなど、多くの欠点がある.ブロガーは怠け者なので、このバグは修復しません~
と言った以上、やってみましょう.今回はマルチスレッドで実現して、ちょうど手を練習しています~
まず考えてみましょう.
サーバを中継局として情報を処理し,クライアントとインタラクティブになる一方でメッセージ転送を行う.
大体の考え方が確定したら、いくつかの通信規則を確定する必要があります.
1. クライアントがサーバと接続を確立した後、ユーザー名を入力してログインする必要があります.ユーザー名がすでに存在する場合、reuseをユーザーにフィードバックし、ユーザーはエラー情報を出力し、終了します.
2. ユーザーが正しいユーザー名を入力すると、通信ができます.通信オブジェクトが選択されていない場合、サーバは情報をフィードバックし、ユーザーに通信オブジェクトの選択を要求します.
3. 通信オブジェクトを選択する方法は、to:usernameを入力し、選択したオブジェクトが存在しない場合は、エラー情報をフィードバックし、再入力します.
4.通信対象が正しく選択されると、双方は接続を確立し、サーバ中継情報により通信する
5.通信中に「quit」が送信されると、メッセージを送信するスレッドが終了し、そのユーザがログインする準備ができていることをサーバに指示し、サーバがそのユーザを削除した後、メッセージをユーザにフィードバックし、ユーザがメッセージを受信するスレッドを終了して終了する
6.AがCと通信中である場合、BがAに情報を送信すると、Aの通信ウィンドウはBとの通信ウィンドウとなり、すなわちBメッセージを受信すると、AからのメッセージはCではなく、Bにデフォルトで送信される
#!/usr/bin/python
'test TCP server'
from socket import *
from time import ctime
import threading #
import re #
HOST = ''
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
def Deal(sock, user):
while True:
data = sock.recv(BUFSIZ) #
if data == 'quit': #
del clients[user]
sock.send(data)
sock.close()
print '%s logout' %user
break
elif re.match('to:.+', data) is not None: #
data = data[3:]
if clients.has_key(data):
chatwith[sock] = clients[data]
chatwith[clients[data]] = sock
else:
sock.send('the user %s is not exist' %data)
else:
if chatwith.has_key(sock): #
chatwith[sock].send("[%s] %s: %s" %(ctime(), user, data))
else:
sock.send('Please input the user who you want to chat with')
tcpSerSock = socket(AF_INET, SOCK_STREAM)
tcpSerSock.bind(ADDR)
tcpSerSock.listen(5)
clients = {} # ->socket
chatwith = {} #
while True:
print 'waiting for connection...'
tcpCliSock, addr = tcpSerSock.accept()
print '...connected from:',addr
username = tcpCliSock.recv(BUFSIZ) #
print 'The username is:',username
if clients.has_key(username): #
tcpCliSock.send("Reuse") #
tcpCliSock.close()
else:
tcpCliSock.send("Welcome!") #
clients[username] = tcpCliSock
chat = threading.Thread(target = Deal, args = (tcpCliSock,username)) #
chat.start() #
tcpSerSock.close()
#!/usr/bin/python
'test tcp client'
from socket import *
import threading
HOST = 'localhost'
PORT = 21567
BUFSIZ = 1024
ADDR = (HOST, PORT)
threads = []
def Send(sock, test): #
while True:
data = raw_input('>')
tcpCliSock.send(data)
if data == 'quit':
break
def Recv(sock, test): #
while True:
data = tcpCliSock.recv(BUFSIZ)
if data == 'quit':
sock.close() # socket
break
print data
tcpCliSock = socket(AF_INET, SOCK_STREAM)
tcpCliSock.connect(ADDR)
print 'Please input your username:',
username = raw_input()
tcpCliSock.send(username)
data = tcpCliSock.recv(BUFSIZ)
if data == 'Reuse':
print 'The username has been used!'
else:
print 'Welcome!'
chat = threading.Thread(target = Send, args = (tcpCliSock,None)) #
threads.append(chat)
chat = threading.Thread(target = Recv, args = (tcpCliSock,None)) #
threads.append(chat)
for i in range(len(threads)): #
threads[i].start()
threads[0].join() # ,send recv , send join, recv 。
もちろん、本プログラムには、通信双方においてAが終了した場合でも、他方のBの通信リストにAが残っている場合でも、Bが登録されたBにメッセージを送信するとエラーが発生するなど、多くの欠点がある.ブロガーは怠け者なので、このバグは修復しません~