Python chat room Instance program sharing

Source: Internet
Author: User
Tags socket error connection reset telnet program
In the previous article we learned the simple Python TCP socket programming, by writing the server side and the client's code to understand the basic Python socket programming model. This article will use an example to enhance the understanding of Socket programming.

One, chat room program requirements
We want to achieve is a simple chat room example, is to allow more than one person to chat together at the same time, everyone sends the message everyone can receive, similar to the function of QQ group, rather than peer-to-peer chat between QQ friends. Such as:

There are two parts of what we want to achieve:

    • Chat Server : is responsible for establishing a Socket connection with a user and broadcasting a message sent by a user to all online users.
    • Telnet Client: user chat clients, you can enter the content of the chat and send, while the other users can display the message record.

Similarly, our message communication uses a TCP connection to ensure reliability. Before you program the server and client, you should first learn about a function--select that implements asynchronous I/O in Python.

Second, Python asynchronous I/O
Python provides asynchronous I/O (asynchronous I/O) in the Select module, similar to the select mechanism under Linux, but with some simplification. I'll start by introducing select and telling you how to use it in Python.

The previous article uses multithreading to handle multi-socket I/O in parallel, and the Select method described here allows you to respond to multiple events and different events from different sockets. For example, you can have select when a socket has data to arrive, or when a socket can write data, or when a socket error occurs when you notify you, the advantage is that you can respond to many sockets at the same time multiple events.

Linux C's Select uses a bitmap to indicate which file descriptor events we want to focus on, Python uses list to represent the file descriptor we monitor, and when an event arrives, a list of file descriptors is returned, indicating that the files have an event arrival. The following simple program means waiting for input from standard input:

Rlist, wlist, elist = Select.select ([Sys.stdin], [], []) print sys.stdin.read ()

The three parameters of the Select method are list types, which represent read events, write events, error events, and the same method return value is also three lists, which contains the events (read, write, exception) that are satisfied. In the above example, since the parameter has only one event Sys.stdin, which means that only the standard input event is concerned, the rlist will only be [Sys.stdin] When the select returns, indicating that the data can be read from stdin, and we use the Read method to read the data.

Of course select is also valid for the socket descriptor, the following example creates a two socket client connection to a remote server, and select is used to monitor which socket has data arrival:

Import Socketimport selectsock1 = Socket.socket (socket.af_inet, socket. SOCK_STREAM) Sock2 = Socket.socket (socket.af_inet, socket. Sock_stream) Sock1.connect ((' 192.168.1.1 ', +)) Sock2.connect ((' 192.168.1.1 ', +)) while 1:  # Await A read event
  
   rlist, wlist, elist = Select.select ([Sock1, Sock2], [], [], 5)  # Test for timeout  if [rlist, wlist, elist] = = [ [], [], []]:    print "Five seconds elapsed.\n"  else:    # Loop through each socket in rlist, read and print the A vailable data for    sock in rlist:      print sock.recv (100)
  

Well, with the foundation above, we can design the chat room server and client.

Third, chat room server
The chat room server mainly completes the following two things:

    • Receiving connections from multiple clients
    • Read messages from each client sick broadcast to other connected clients

We define a list-type variable, connection_list, which represents a readable event that listens to multiple socket events, and the code for using Select to process multiplexed I/O with our server described above is as follows:

# Get The list sockets which is ready for be read through selectread_sockets,write_sockets,error_sockets = Select.select (C Onnection_list,[],[])

When select returns, it indicates that there is readable data on the read_sockets, which is divided into two cases:

1, if the main socket (that is, the server started to create a socket, always in the listening state) has data readable, indicating that a new connection request can be received, you need to call the Accept function to receive the new client connection, and broadcast its connection information to other clients.
2, if the other sockets (that is, the client has established a connection to the sockets) has data readable, then the client sends a message to the server side, using the RECV function to read the message, and forward the message to all other connected clients.
The above two situations involve the process of broadcasting messages, which means that the messages obtained from a socket are sent through each socket of the connection_list (in addition to itself and the primary socket):

def broadcast_data (sock, message):  #Do not send the message to master socket and the client who have send us the Messa GE for  sockets in Connection_list:    if socket! = Server_socket and Socket! = Sock:      try:        socket.send (Messag e)      except:        # Broken socket connection may, chat client pressed CTRL + C for example        socket.close ()        Conne Ction_list.remove (socket)

If the send fails, we assume that a client has disconnected and that the socket sickness is removed from the connection list.

The full chat room server source code is as follows:

# TCP Chat Server import socket, select #Function to broadcast chats messages to all connected Clientsdef Broadcast_data (s Ock, message): #Do not send the message to master socket and the client who have send us the message for socket in Connec        Tion_list:if Socket! = Server_socket and Socket! = sock:try:socket.send (message) except: # Broken socket connection may, chat client pressed CTRL + C for example Socket.close () Connection_list.rem  Ove (socket) If __name__ = = "__main__": # List to keep track of socket descriptors connection_list = [] Recv_buffer = 4096 # advisable to keep it as an exponent of 2 PORT = Server_socket (socket.socket, socket).  SOCK_STREAM) # effect, why? Server_socket.setsockopt (socket. Sol_socket, SOCKET. SO_REUSEADDR, 1) server_socket.bind (("0.0.0.0", PORT)) Server_socket.listen () # ADD server socket to the list of Rea dable Connections Connection_list.append (server_socket) print "Chat server started on port" + STR (port) while 1: # Get The list sockets which is ready for be read Throu       GH Select read_sockets,write_sockets,error_sockets = Select.select (connection_list,[],[]) for sock in Read_sockets: #New connection If sock = = Server_socket: # Handle The case in which there is a NEW connection recieved Through Server_socket sockfd, addr = Server_socket.accept () connection_list.append (SOCKFD) print "Cli ENT (%s,%s) connected "% addr Broadcast_data (SOCKFD," [%s:%s] entered room\n "% addr) #Some I Ncoming message from a client else: # Data recieved from client, process it try: #In Windows, Sometimes when a TCP program closes abruptly, # a "Connection Reset by Peer" exception would be thrown da Ta = sock.recv (recv_buffer) if Data:broadcast_data (sock, "\ r" + ' < ' + str (sock.getpeername ()) + ' & Gt           ' + data ')              Except:broadcast_data (sock, "client (%s,%s) is offline"% addr) print "Client (%s,%s) I s offline "% addr Sock.close () connection_list.remove (sock) continue Server_socket.close ()

Run the program under the console:

$ python chat_server.py Chat server started on port 5000

Iv. Chat Room Client
We write a client program that can connect to the server above to complete the process of sending messages and receiving messages. Here are two main things to do:

    • Listen to the server if there is a message sent.
    • Check the user's input, if the user enters a message that needs to be sent to the server

There are two I/O events to listen to: a socket and standard input to the server, and we can use Select to do the following:

Rlist = [Sys.stdin, S]     # Get The list sockets which is Readableread_list, write_list, error_list = Select.select (rlis T, [], [])

The logic is very simple, if the Sys.stdin has data readable, indicating that the user input data from the console and press ENTER, then read the data from the standard input and send to the server, if the socket connected to the server has data readable, indicating that the server sends a message to the client, then the The socket receives data. The complete client code with some hints and exception handling is as follows:

# telnet Program Exampleimport socket, select, String, sys def prompt (): Sys.stdout.write ('
 
  
 ') Sys.stdout.flush () #main functionif __name__ = = "__main__": if (len (SYS.ARGV) < 3): print ' Usage:python telnet.py hostname Port ' sys.exit () host = sys.argv[1] Port = Int (sys.argv[2]) s = Socket.socket (socket.af_ine T, Socket.  SOCK_STREAM) S.settimeout (2) # Connect to remote host Try:s.connect ((host, port)) Except:print ' Unable to Connect ' sys.exit () print ' Connected to remote host.     Start sending messages ' prompt () while 1:rlist = [Sys.stdin, S] # Get the list sockets which is readable Read_list, write_list, error_list = Select.select (rlist, [], []) for sock in Read_list: #incoming messag E from remote server if sock = = S:data = SOCK.RECV (4096) if not Data:print ' \ndisconnected              From Chat server ' Sys.exit () Else: #print data sys.stdout.write (data) prompt () #user entered a message else:msg = Sys.stdin.reaDline () s.send (msg) prompt () 
 

You can run the code under multiple endpoints:

$ python telnet.py localhost 5000Connected to remote host. Start sending messages
 
  
   
   Hello
  
   
    
    I am fine< (' 127.0.0.1 ', 38378) > OK good
   
    
  
   
 
  

Information displayed on the other terminal:

 
  
   
   [127.0.0.1:39339] entered room< (' 127.0.0.1 ', 39339) > hello< (' 127.0.0.1 ', 39339) > I am Fine
  
   
    
    OK good
  
   
 
  

Summarize
The above code notes two points:

1. The Chat room client code cannot run under Windows because the code uses select to listen for both the socket and the input stream, under Windows The Select function is provided by the Winsock library and cannot handle file descriptors that are not defined by Winsock.
2, the client code also has a flaw is that when a client enters a message but has not been sent out, the server also sends a message, which will flush out the message that the client is entering. This is currently not a solution, the only solution is to use a terminal library like ncurses to make the user input and output independent, or write a GUI program.
In this paper, a chat room example is further studied under the Python Socket programming.

  • Related Article

    Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.