Skip to content

Instantly share code, notes, and snippets.

@amcgregor
Forked from anonymous/client1.py
Created December 18, 2012 22:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amcgregor/4332627 to your computer and use it in GitHub Desktop.
Save amcgregor/4332627 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
from __future__ import print_function
# This makes Python use the newer print() syntax.
import socket
import time
import sys
import twitter
from weakref import proxy
class Client(object):
def __init__(self, server, socket, ip, port):
super(Client, self).__init__()
self.server = proxy(server) # this helps Python manage memory
self.socket = socket
self.ip = ip
print("Received connection from: ", ip, ":", port, sep='')
def close(self):
"""Close the connection and update the server."""
print("Goodbye from", self.ip)
# Don't client.send here; the connection may already be dead!
self.socket.close()
# Remove from the server tracking of current connections.
del self.server.clients[self.socket]
def send(self, data):
"""Send data to the client."""
# We wrap it in str() here (for Python 2) because sockets only communicate in binary data.
# On Python 3 you'd use bytes() instead.
self.socket.send(str(data))
def read(self):
"""There is data available for reading."""
data = self.socket.recv(1024)
# this is bad since \n won't actually return!
# recv(1024) either gets exactly 1KB of data or returns when the client disconnects
# Implementing a line-based buffer is left as an exercise for the reader!
# Continuing with the assumption that data is a line of text, not a 1KB chunk.
print("CLIENT_REQUEST", self.ip, ">>", data)
# Now, manually checking for each command as a substring is not very efficient.
# If we assume a command is always the prefix of the string with at least one space
# separating the argument(s)...
command, sep, argument = data.partition(' ')
fn = getattr(self, 'cmd_' + command, None)
if fn:
if sep: # sep will evaluate to False if there was no space, otherwise it will be a space
fn(argument)
return
fn()
return
self.send("Unknown command: " + command + "\n")
def menu(self):
self.send('''##############################
Choose option from the menu:
##############################
1) Open Shell
2) Lists files in current working directory
3) Get Twitter feed from <uid>
4) Shuts down socket!
#############################
''')
def cmd_shell(self):
'''This function creates a shell with basic system commands.'''
pass
def cmd_ls(self):
'''This function lists which current directory the client is in.'''
def cmd_twitter(self, user):
'''This function gets twitter with uid given as argument.'''
status = self.server.api.GetUserTimeline(count=5, screen_name=user)
output = [message.text for message in status]
for tweet in output:
self.send(tweet)
def cmd_exit(self):
self.send("Bye!")
self.close()
def cmd_time(self):
"""return the local time"""
date = time.asctime()
self.send(date)
def cmd_help(self):
'''This function returns help for commands no args given.'''
# The indentation would have been sent, too!
self.send('''shell open a shell to the host machine and gain access to system shell commands.
ls lists the file in the current working directory.
twitter this command requires 1 argument <id> and will fetch the last 5 tweets.
exit will close the connection.
help will open up the current help menu.
time will get local time.
''')
class Server(object):
def __init__(self, host, port):
super(Server, self).__init__()
self.api = twitter.Api()
self.socket = socket.socket()
self.socket.bind((host, port))
self.socket.listen(5) # 5 is the 'backlog' size
self.clients = {}
def start(self):
# This shouldn't be a while True; there's no way to exit!
while True:
# Prepare the list of sockets which can be read from or have errors.
listeners = [self.socket] + self.clients.keys()
readers, writers, errors = socket.select(listeners, self.connections, listeners)
if errors:
1/0 # die horribly, something went wrong; TODO: handle this better ;)
if self.socket in readers:
# A new connection is available since our server socket can be 'read'.
socket, (ip, port) = self.socket.accept()
# Create a new Client object and let it know which server and client socket to use.
client = Client(self, socket, ip, port)
# Keep track of the connection.
self.clients[socket] = client
for socket in readers:
if socket is self.socket: continue # skip the server socket
# Now all we have are sockets with outstanding data to read.
self.clients[socket].read()
if __name__ == '__main__':
service = Server('127.0.0.1', 5050)
service.start()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment