Multi-user full-duplex Chat Humble edition
A simple implementation of communication between two clients, the client sends a message, first received by the server, and then forwarded to another client.
This version is very primitive, it only realizes the simplest chat, there are a lot of places to pay attention to.
Work steps:
- Server-side operation
- A client runs, the connection succeeds after entering the user name, the server will save the user name in a dictionary, the corresponding relationship of the dictionary is
username --> socket
- After entering the user name, the client needs to determine a chat user, client input, and
To:user
if the client sends other text, it will receive a prompt from the server: "Nobody is chatting with you. Maybe the one talked with are talking with someone else "
- When two clients connect successfully, they can send messages to each other
The server-side code is as follows:
#!/usr/bin/python#coding: Utf-8#server. PY fromSocketImport * fromTimeImportCTimeImportThreadingImportReHOST= "'PORT= 9999Bufsiz= 1024x768ADDR=(Host,port) Tcpsersock=Socket (Af_inet,sock_stream) tcpsersock.bind (ADDR) Tcpsersock.listen (5) clients={}# username SocketChatwith={}# User1.socket-User2.socket# Clients dictionary that records the corresponding relationship between the user name and the socket of the connected client# Chatwith The correspondence between the two sides of the communication is recorded in the dictionary# messagetransform () processing the text sent after the client determines the user name# There are only four types of text:# None# Quit# To:someone# Other textdefMessagetransform (Sock,user): while True: Data=SOCK.RECV (Bufsiz)if notDataifChatwith.has_key (sock): Chatwith[sock].send (data)delChatwith[chatwith[sock]]delChatwith[sock]delClients[user] Sock.close () Break ifData==' Quit ': Sock.send (data)ifChatwith.has_key (sock): Data= '%s. ' %Data chatwith[sock].send (data)delChatwith[chatwith[sock]]delChatwith[sock]delClients[user] Sock.close () Break elifRe.match (' ^to:.+ ', data) is not None: Data=data[3:]ifClients.has_key (data):ifData==User:sock.send (' please don\ 'T try to talk with yourself. ')Else: Chatwith[sock]=Clients[data] Chatwith[clients[data]=SockElse: Sock.send (' The user%sis not exist ' %DataElse:ifChatwith.has_key (sock): Chatwith[sock].send (' [%s] %s: (%s) ' %(CTime (), User,data))Else: Sock.send (' Nobody is chating with you. Maybe the one talked with are talking with someone else ')# After each client connection, a new thread will be started# You need to enter a user name after successful connection# The user name entered may be:# already exists# (Client direct input CTRL + C exit)# Legal User namedefConnectthread (sock,test):# client ' s socketUser= None while True:# receive the usernameUsername=SOCK.RECV (Bufsiz)if notUsername# The client logout without input a name Print(' The client logout without input a name ') Break ifClients.has_key (username):# username existedSock.send (' Reuse ')Else:# correct usernameSock.send (' OK ') Clients[username]=Sock# username SocketUser=Username Break if notUser:sock.close ()return Print(' The username is:%s' %User# Get the correct usernameMessagetransform (Sock,user)if __name__==' __main__ ': while True:Print(' ... Waiting for CONNECTION ') Tcpclisock, addr=Tcpsersock.accept ()Print(' CONNECTED from: ', addr) Chat=Threading. Thread (target=Connectthread, args=(Tcpclisock,None)) Chat.start ()
The client code is as follows:
#!/usr/bin/python#coding: Utf-8#client. PY fromSocketImport * fromTimeImportCTime# from Termios import Tcflush,tciflushImportThreadingImportSyshost= ' 127.0.0.1 'PORT= 9999Bufsiz= 1024x768ADDR=(Host,port) Tcpclisock=Socket (Af_inet,sock_stream) Tcpclisock.Connect(ADDR)" "because each client receives messages and sends messages independently of each other,So here we'll split the two, turn on two threading" "defSend (sock,test): while True:Try: Data= Raw_input() sock.send (data)ifData==' Quit ': Break except Keyboardinterrupt: Sock.send (' Quit ') Break defRECV (sock,test): while True: Data=SOCK.RECV (Bufsiz)ifData==' Quit. ':Print(' he/she logout ')Continue ifData==' Quit ': Break Print('%s' %Dataif __name__==' __main__ ':Print(' Successful connection ') while True: username= Raw_input(' Your name (press only Enter to quit): ') Tcpclisock.send (username)if notUsername Break # username is not NoneResponse=TCPCLISOCK.RECV (Bufsiz)ifResponse==' Reuse ':Print(' The name is reuse, please set a new one ')Continue Else:Print(' welcome! ') Break if notUsername:tcpCliSock.close () recvmessage=Threading. Thread (target=Recv, args=(Tcpclisock,None)) SendMessage=Threading. Thread (target=Send, args=(Tcpclisock,None)) Sendmessage.start () Recvmessage.start () Sendmessage.join () Recvmessage.join ()
Summarize:
function is simple, the follow-up will be improved. There are a lot of places to be aware of here.
For example, two client a successfully connected, and client B chat. A send a message when the direct Input ctrl+c
exit program ( sendMessage
thread will end), I will simulate this situation as a send Quit
logout. After the server receives a logout message, it sends back a Quit
successful logout ( recvMessage
thread end) to the a,a. In addition, if A and b establish a chat relationship, it is necessary to contact the relationship, the server sent Quit.
to B,b will continue to receive information, but the server side of the chatwith
dictionary has no A.socket --> B.socket
relationship.
However, there are many unresolved issues, such as client A does not enter the information, directly click the Close button to exit, there will be an exception (chat with the B client will crash).
If there is currently a a-->b chat relationship, there is a C login, and the c-->a chat relationship is determined, then a will chat with C, then client B will be suspended.
The main problem is the client's irregular logout response, currently solves some of the problems, but there should be a lot of flaws.
Python enables multi-user full-duplex chat (one-to-one)