Provided below is the source code for a relatively simply Python chat client and server program solution which serves as a functional example of socket programming. I apologize for the squished formatting and lack of white space in the source viewer, but viewing the source directly from the text box button should make it a little more readable.
The first file is the server which should run fine on any modern Linux operating system. The client should also be run on Linux, and can connect to the server from any networked computer on the same subnet. I have had some success connecting this client/server to a similar program written in Java, though you may need to play around with the buffer sizes in each.
I also included a few custom commands for the client to execute. The comments in the source should be sufficient to explain what is going on to experienced Python programmers. I know I am terrible for this, but I cannot remember from where I took the original source code before modifying it. Enjoy!
Client.py
import socket
import sys
import time
# Default connection parameters
client_host = "localhost" #Address of server
client_port = int(9020) #Port used by server
time = time.strftime('%l:%M %p %Z on %b %d, %Y') # Client start time
login_time = str(time) #Convert client start time to string
print "Client initiated at: " + login_time
# Override default parameters (optional command line arguments)
if(len(sys.argv) > 1): #One parameter argument provided by client
client_host = sys.argv[1] #Override host server IP default "localhost" w/ first argument
if(len(sys.argv) > 2): #Two parameter arguments provided by client
client_port = int(sys.argv[2]) #Override host port number w/ second argument
# Set up client socket connection
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((client_host, client_port))
# Loop indefinitely while client running
while 1:
server_data = client_socket.recv(2048) #Receive server data into buffer
client_data = server_data.lower() #Lowercase received data for processing
# Process received data
if (client_data == 'adios'):
client_socket.close() #Close socket connection
break;
else:
print "(SERVER REPLY)",server_data #Feedback from server
server_data = raw_input("SEND TO SERVER>> ") #Get client input from keyboard
client_data = server_data.lower() #Lowercase client input
# Sent commands
if (client_data != 'adios'):
client_socket.send(server_data + "\r\n") #Send data to server if not "adios"
else:
client_socket.send(server_data + "\r\n")
client_socket.close #Otherwise close the socket connection
break;
Server.py
import os
import re
import socket
import sys
import time
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create socket
server_socket.bind(("", 9020)) #Bind server to this socket
server_socket.listen(4) #Max number of queued connections
# Welcome message
print "TCP chat server now awaiting client connection on port 9020..."
chat_log = [] #Contains chat log
time = time.strftime('%l:%M %p %Z on %b %d, %Y') #Server start time formatted nicely
start_time = str(time) #Convert server start time to string
username = "ChatUser" #Default server username if user does not provide one
# Support ~2^x client connections, where x is the number of process forks
os.fork()
os.fork()
os.fork()
# This variable contains the help documentation for the "help" command
chatHelp = ("The chat server accepts the following commands:\n"
+ "adios Closes the program\n"
+ "connection Shows client connection info (IP, port)\n"
+ "get Returns complete chat log\n"
+ "getrange <#> <#> Get chat log entries from <#> to <#> (starts at 1)\n"
+ "help Lists valid commands\n"
+ "name: <text> Sets your username to <text>\n"
+ "test: <text> Echo data back to you <text>\n"
+ "time Shows time when server was initiated\n"
+ "push: <text> Add <text> to chat log\n"
+ "save Save chat log to file\n")
while 1:
# Accept connection
client_socket, address = server_socket.accept()
# Print connection info from client for server log
print "Received connection from client at", address
# Used in the connection command function (client request) below
connection = str(address)
# Send welcome string to client
client_socket.send("Welcome to Nigel's chat room! You are logged in as ChatUser.\n Type help for a list of valid commands.\n")
# Loop indefinitely while server running
while 1:
data = client_socket.recv(2048) #Receive client data into buffer
process_data = data.lower() #Lowercase received data for processing
print "Data received from client>>", process_data #Print data received from client for log reference
# Functions for the received commands (I use the find library to reduce compatibility errors with other languages)
# ---"adios" command function---
if (process_data.find("adios") == 0):
client_socket.close() #Close socket connection
print "<Ctrl+C to exit.>>"
break;
# ---"connection:" command function---
elif(process_data.find("connection") == 0):
client_socket.send("Client connection info: " + connection + "\n")
print "User requested connection information"
# ---"getrange" command function w/ regular expression filtering (must be BEFORE "get" command function)---
elif(re.match(r'getrange\s+(\d+)\s+(\d+)',process_data)): # Regex to find correct match with dynamic numbers input
match = re.match(r'getrange\s+(\d+)\s+(\d+)',process_data)
getValue = "Chat log from range "+ match.group(1) + " and " + match.group(2) + ":\n" # Grab first and second range number provided by client
if(len(chat_log) >= int(match.group(1)) and len(chat_log) >= int(match.group(2))): # Check to see if chat log extends to given range
count = int(match.group(1)) - 1
while(count < int(match.group(2))):
getValue += chat_log[count] + "\n"
count += 1
else:
getValue += "<>\n" #No data in range provided by client
client_socket.send(getValue) #Send results to client
# ---"get" command function---
elif(process_data.find("get") == 0):
log = "Chat log: \n"
for item in chat_log:
log += item+" \n"
client_socket.send(log)
# ---"help:" command function---
elif(process_data.find("help") == 0):
client_socket.send(chatHelp + "\n")
print "User requested help"
# ---"name:" command function---
elif(process_data.find("name:") == 0):
username = data[5:].strip() #Only grab the value client set (not "name:")
client_socket.send("Username set to: " + data[5:] + "\n")
# ---"test:" command function---
elif(process_data.find("test:") == 0):
client_socket.send(data[5:]+"\n") #Echo last 5 elements to client
print data
# ---"time" command function---
elif(process_data.find("time") == 0):
client_socket.send("Chat server was started at: " + start_time + "\n")
print "User requested server start time"
# ---"save" command function---
elif(process_data.find("save") == 0):
print "(Saving chat log to file)"
client_socket.send("Saving chat log to file..." + "\n")
filename = "chat.log"
file = open(filename,"w") #Create file
for item in chat_log: #Loop through elements in chat_log
file.write("%s\n" % item) #Write elements one by one on a new line
file.close() #Close/write file
# ---"push" command function---
elif(process_data.find("push:") == 0):
print "(Pushing data to chat log)"
if(username != ""):
chat_log.append(username + ": " + data[5:].strip()) #Save actual chat text to log (not "push:")
else:
chat_log.append(data[5:].strip())
client_socket.send("OK\n")
else:
print "<<Unknown Data Received>>",data #Server log
try:
client_socket.send("Unrecognized command: " + data + "") #Advise client of invalid command
except socket.error, e:
print "<<Ctrl+C to exit>>" #Server log
break;