A simple chat with Sockets using Python

The following work was developed during the Computer Network class given by professor Carlos Viegas at the Federal University of Rio Grande do Norte. The group was composed of Lenildo and me.

The assignment consisted of implementing a simple chat with Sockets based on a client/server communication. We also needed to insert some functionalities into the application, like changing the name of the user, listing the active clients connected to the chat and even to start a private chat with a specific user. There is no direct communication between clients, all messages need to pass through the server to reach the other end.

Now let’s start to talk about the code!

The strategies to create the system involves using threads to communicate the clients and server parallelly with the help of sockets:


# import libraries
from socket import *
from threading import Thread # thread

Beginning with the server, the following lines were used for the main configuration. It is needed to describe the server IP, port and operating protocol (TCP in our case):


# Server IP
serverName = ''
# Server port to connect
serverPort = 12000
# TCP protocol
serverSocket = socket(AF_INET,SOCK_STREAM)
# Bind the Server IP with its port
serverSocket.bind((serverName,serverPort))
# Ready to receive connections
serverSocket.listen(1) 

Next, a loop is started and it creates a new thread each time a client connects to the server:


counter = 0
while 1:
	# Accept clients connections
	# This line waits until a new client is connected
	connectionSocket, addr = serverSocket.accept()
	# Information order: Socket object, client Nick, Is connected, IP
	clients.append([connectionSocket,0,0,addr])
	# Call thread to manage client
	t = Thread(target=clientManager, args=(connectionSocket,counter,))
	t.start()
	counter += 1
# Finish server Socket
serverSocket.close()
begins

The thread to manage the clients is shown below. It starts by receiving the client nickname at its first message. After the thread enters in a loop to manage the next messages the client will send, if it is not a special command such as “name(bob)” or “list()”, the message will be sent to all other connected clients. The “name()” command changes the current name of the client and “list()” returns all available connections to the client.


# Thread to manage each client separetly
def clientManager(connectionSocket,t_id):
	# Receive the clients nick
	sentence = connectionSocket.recv(1024)
	# Nick stays at position 1
	clients[t_id][1] = sentence
	identification = "Cliente %s has logged in." % (sentence)
	print identification
	connectionSocket.send(identification) 

	while 1:
		message = connectionSocket.recv(1024)
		serv_response = "%s sent: %s" % (clients[t_id][1],message)
		print message
		# Change nickname
		if "name(" in message:
			new_name = message.split('name(')
			new_name = new_name[1].split(')')
			new_name = new_name[0]
			nick_change = "%s changed to: %s"%(clients[t_id][1],new_name)
			clients[t_id][1] = new_name
			print "New nick is: %s"%new_name
			for i in range(0, len(clients)):
				if clients[i][2]==0:
					clients[i][0].send(nick_change)
		# Send list of connected clients
		elif "list()" in message:
			for i in range(0, len(clients)):
				if clients[i][2]==0:
					send_list = "name: %s ip: %s port: 12000\n"%(clients[i][1],clients[i][3])
					clients[t_id][0].send(send_list)
		#Send the message to all clients for a global chat
		else:
			for i in range(0, len(clients)):
				if clients[i][2]==0:
					clients[i][0].send(serv_response)
			if message == "close()":
				clients[t_id][2]=-1
				print "Client %s left the room."%clients[t_id][1]
				break
	connectionSocket.close() # Finishes the socket connection<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

Subsequently, the client code configuration is very similar to the server as below:


serverName = 'localhost'
serverPort = 12000
clientSocket = socket(AF_INET,SOCK_STREAM)
# Main configuration difference between client and server
clientSocket.connect((serverName, serverPort))
sentence = raw_input('Type your nickname: ')
clientSocket.send(sentence)

A thread is started to wait for the server messages without being stopped by the “raw_input()” function. The loop keeps the connection alive until the client types “close()”.


t = Thread(target=receiveMessage, args=(clientSocket,))
t.start()
while 1:
	# Message input to the server
	sentence = raw_input('')
	clientSocket.send(sentence)
	if sentence == "close()":
		break
# Finish client Socket
clientSocket.close() 

The thread to receive messages parallelly from the server:

# Print the received messages from the server independently
def receiveMessage(clientSocket):
	while 1:
		msgRecebida = clientSocket.recv(1024)
		print '%s' % (msgRecebida)

The following images show a demonstration of the chat communication working. The image below starts the server at the port 12000.

p1

After, a client connects and types his nickname.

p2

Another client connects to start a conversation. When the conversation is finished, they both exit the chat.

p4

The next image shows the server terminal, it also receives the ongoing chat between the two users (or more). It also lists the available connections with “list()”. The whole system finishes with a “close()” at the clients and then at the server.

p5

The source code can be found on Github:

https://github.com/YangTavares/Computer_Network/tree/master/socket_chat

There is also an enhanced implementation of the socket chat available on:

https://github.com/YangTavares/Computer_Network/tree/master/private_socket_chat

In the improved version, two users are able to start a private chat. Both users on a private conversation can change messages that are not going to appear on the global chat to all users connected. As before, the server is always between the exchange of messages.

The next images quickly exemplify the private chat function. Below, user “yang” requests “lenildo” to a private chat:

private1

“lenildo” is asked if he wants to start a private chat with “yang”.

private2

It is important to mention that the implementations described in this post may have some bugs, but they serve the purpose of the proof of concept.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s