socket python 收 发 线程_基于socketserver的python多线程聊天室

"""everytime before you send msg, encode it

after you rec msg, decode it!

"""

import socketserver

import re

import socket

class ClientError(Exception):

"An exception thrown because the client gave bad input to the server."

pass

class PythonChatServer(socketserver.ThreadingTCPServer):

"the server class"

def __init__(self, server_address, RequestHandlerClass):

"""Set up an initially empty mapping between a user' s nickname

and the file-like object used to send data to that user."""

socketserver.ThreadingTCPServer.__init__(self, server_address, RequestHandlerClass)

self.users = {}

class RequestHandler(socketserver.StreamRequestHandler):

"""Handles the life cycle of a user's connection to the chat server: connecting,

chatting, running server commands, and disconnecting."""

NICKNAME = re.compile('^[A-Za-z0-9_-]+$') #regex for a valid nickname

def handle(self):

"""Handles a connection: gets the user's nickname, then

processes input from the user until they quit or drop the

connection."""

self.nickname = None

self.privateMessage("Who are you?")

nickname=self._readline()

done = False

try:

self.nickCommand(nickname)

self.privateMessage('Hello %s, welcome to the Python Chat Server.' % nickname)

self.broadcast('%s has joined the chat.' %nickname,False)

#print('%s has joined the chat.' %nickname) #print in server

except (ClientError) as error:

self.privateMessage(error.args[0])

done = True

except socket.error:

done = True

#Now they're logged in, let them chat

while not done:

try:

done = self.processInput()

except (ClientError) as error: #wrong:ClientError(error)

self.privateMessage(str(error))

except socket.error:

done = True

def finish(self):

"""Automatically called when handle() is done!!!"""

if self.nickname:

#The user successfully connected before disconnecting.

#Broadcast that they're quitting to everyone else.

message = '%s has quit.' % self.nickname

if hasattr(self, 'partingWords'):

message = '%s has quit: %s' % (self.nickname, self.partingWords)

self.broadcast(message, False)

#Remove the user from the list so we don't keep trying

#to send them messages.

if self.server.users.get(self.nickname):

del(self.server.users[self.nickname])

self.request.shutdown(2)

self.request.close()

def processInput(self):

"""Reads a line from the socket input and either runs it as a

command, or broadcasts it as chat text."""

done = False

l = self._readline()

command, arg = self._parseCommand(l)

if command:

done = command(arg)

else:

l = ' %s\n' % (self.nickname, l)

self.broadcast(l)

return done

def nickCommand(self,nickname):

"Attempts to change a user's nickname."

if not nickname:

raise ClientError('No nickname provided.')

if not self.NICKNAME.match(nickname):

raise ClientError('Invalid nickname: %s' % nickname)

if nickname == self.nickname:

raise ClientError('You\'re already known as %s.' % nickname)

if self.server.users.get(nickname,None):

raise ClientError('There\'s already a user named "%s" here.' %nickname)

oldNickname = None

if self.nickname:

oldNickname=self.nickname

del(self.server.users[self.nickname])

self.server.users[nickname]=self.wfile

self.nickname=nickname

if oldNickname:

self.broadcast('%s is now known as %s' % (oldNickname, self.nickname))

def quitCommand(self, partingWords):

"""Tells the other users that this user has quit, then makes

sure the handler will close this connection."""

if partingWords:

self.partingWords = partingWords

#Returning True makes sure the user will be disconnected.

return True

def namesCommand(self, ignored):

"Returns a list of the users in this chat room."

self.privateMessage(', '.join(self.server.users.keys()))

#Below are helper methods

def broadcast(self, message, includeThisUser=True):

"""Send a message to every connected user, possibly exempting the

user who's the cause of the message."""

message = self._ensureNewline(message)

for user, output in self.server.users.items():

if includeThisUser or user != self.nickname:

output.write(message.encode('utf-8'))

def privateMessage(self, message):

"Send a private message to this user."

self.wfile.write(self._ensureNewline(message).encode('utf-8')) #must encode before send

def _readline(self):

"Reads a line, removing any whitespace."

return self.rfile.readline().strip().decode('utf-8') #must decode after rec

def _ensureNewline(self, s):

"Makes sure a string ends in a newline."

if s and s[-1] !='\n':

s += '\r\n'

return s

def _parseCommand(self, input):

"""Try to parse a string as a command to the server.If it's an

implemented command, run the corresponding method.

input /xxx, runs xxxCommand"""

commandMethod, arg = None, None

if input and input[0]=='/':

if len(input)

client:

import socket

import select

import sys

import os

from threading import Thread

class ChatClient:

def __init__(self, host, port, nickname):

self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

self.socket.connect((host, port))

self.input = self.socket.makefile('rb', 0)

self.output = self.socket.makefile('wb', 0)

#Send the given nickname to the server.

authenticationDemand = self.input.readline().decode('utf-8')

if not authenticationDemand.startswith("Who are you?"):

raise Exception ("This doesn't seem to be a Python Chat Server.")

self.output.write((nickname + '\r\n').encode('utf-8'))

response = self.input.readline().strip().decode('utf-8')

if not response.startswith("Hello"):

raise Exception (response)

print(response)

#Start out by printing out the list of members.

self.output.write(('/names\r\n').encode('utf-8'))

print("Currently in the chat room:", self.input.readline().decode('utf-8').strip())

self.run()

def run(self):

"""Start a separate thread to gather the input from the

keyboard even as we wait for messages to come over the

network. This makes it possible for the user to simultaneously

send and receive chat text."""

propagateStandardInput = self.PropagateStandardInput(self.output)

propagateStandardInput.start()

#Read from the network and print everything received to standard

#output. Once data stops coming in from the network, it means

#we've disconnected.

inputText = True

while inputText:

inputText = self.input.readline().decode('utf-8')

if inputText:

print (inputText.strip())

propagateStandardInput.done = True

class PropagateStandardInput(Thread):

"""A class that mirrors standard input to the chat server

until it's told to stop."""

def __init__(self, output):

"""Make this thread a daemon thread, so that if the Python

interpreter needs to quit it won't be held up waiting for this

thread to die."""

Thread.__init__(self)

self.setDaemon(True)

self.output = output

self.done = False

def run(self):

"Echo standard input to the chat server until told to stop."

while not self.done:

inputText = sys.stdin.readline().strip() #no need to decode when read from stdin

if inputText:

self.output.write((inputText + '\r\n').encode('utf-8'))

if __name__ == '__main__':

import sys

#See if the user has an OS-provided 'username' we can use as a default

#chat nickname. If not, they have to specify a nickname.

try:

import pwd

defaultNickname = pwd.getpwuid(os.getuid())[0]

except ImportError:

defaultNickname = None

if len(sys.argv) 3:

nickname = sys.argv[3]

else:

#We must be on a system with usernames, or we would have

#exited earlier.

nickname = defaultNickname

ChatClient(hostname, port, nickname)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值