Python Chat Server

Reply

Join Date: May 2007
Posts: 3
Reputation: JohnMG is an unknown quantity at this point 
Solved Threads: 0
JohnMG JohnMG is offline Offline
Newbie Poster

Python Chat Server

 
0
  #1
May 16th, 2007
Hello! This is my first post. I've put this up on several other forums, but this one seems slightly more active (python-forum.org is a snooze-fest). I have been learning python for a few months and decided to make a chat server that you connect to through telnet. It's working fine so far, but I just want to get feedback from people who know the language well. The code is no-doubt sloppy and I'm sure there are a TON of better and cleaner ways to do what I'm doing. I want all the criticism you have to offer .

PS. - I am deliberately not using Twisted. I want this to be as functional as possible using only the standard library.

  1. #!/usr/bin/python
  2.  
  3.  
  4. ## Home Network Chat Server (HNCS) version 2.0
  5. ## Copyright (C) 2007 John M. Graff
  6. ##
  7. ## This program is free software; you can redistribute it and/or
  8. ## modify it under the terms of the GNU General Public License
  9. ## as published by the Free Software Foundation; either version 2
  10. ## of the License, or (at your option) any later version.
  11. ##
  12. ## This program is distributed in the hope that it will be useful,
  13. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ## GNU General Public License for more details.
  16. ##
  17. ## You should have received a copy of the GNU General Public License
  18. ## along with this program; if not, write to the Free Software
  19. ## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20.  
  21.  
  22.  
  23. ################################################
  24. ## Imports, Constants
  25. ################################################
  26. from time import *
  27. from SocketServer import ThreadingTCPServer, BaseRequestHandler
  28.  
  29.  
  30. endl = '\r\n'
  31. backspace = '\b'
  32. creturn = '\r'
  33. tab = '\t'
  34. space = ' '
  35.  
  36. maxname = 8
  37. packet = 1024
  38.  
  39. HOST = ''
  40. PORT = 65438
  41. ADDRESS = (HOST, PORT)
  42.  
  43. connections = {}
  44. roomlist = {}
  45. #################################################
  46.  
  47.  
  48. ##################################################
  49. ## Big Strings
  50. ##################################################
  51. ## This stuff is self-explanatory. Any one of these
  52. ## can be changed to whatever you want. The 'artwork'
  53. ## variable is fun to play with.
  54.  
  55. artwork = """ ,--.!,\r
  56. __/ -*-\r
  57. ,d08b. '|` HNCS version 2.0\r
  58. 0088MM (c)2007 J.Graff\r
  59. `9MMP'\r
  60. """
  61.  
  62. info = '''\r\n
  63. ---------------------------------------------------\r
  64. INFO\r
  65. ---------------------------------------------------\r
  66. Home Network Chat Server (HNCS) is an open source\r
  67. and freely distributable chatserver written and\r
  68. maintained by John M. Graff in the Python scripting\r
  69. language ([url]http://www.python.org[/url]) and licensed under\r
  70. the GPL (see [url]http://www.gnu.com[/url] for details).\r
  71. \r\n
  72. Source code is available upon request. E-mail the\r
  73. author at [email]jmgraff@student.ysu.edu[/email] for more informa-\r
  74. tion.\r
  75. ----------------------------------------------------\r\n'''
  76.  
  77. clientHelp = '''\r
  78. -----------------------------------------------------\r
  79. COMMANDS\r
  80. -----------------------------------------------------\r\n
  81. 'c' clear screen\r
  82. 'w' print userlist\r
  83. 'i' info about this program\r
  84. 'l' list of rooms\r
  85. 'r' list of people in current room\r
  86. 'q' disconnect\r
  87. '?' show this menu\r
  88. <Enter> type & send a message\r\n
  89.  
  90. NOTE: Windows users only need to press \r
  91. the key. UNIX/Linux/BSD users must press\r
  92. <Enter> after the key.\r
  93. -----------------------------------------------------\r'''
  94.  
  95. gpl = '''HNCS 2.0, Copyright (C) 2007 John M. Graff\r
  96. HNCS comes with ABSOLUTELY NO WARRANTY; This is free\r
  97. software,and you are welcome to redistribute it under\r
  98. the terms and conditions of the GPL.\r\n
  99. See [url]http://www.gnu.com[/url] for details.;\r'''
  100.  
  101. login = '''\r\nWelcome to the server!\r\n
  102. Before you start, choose a Nickname.(Max 8 characters)\r
  103. If it's too long or already in use, you'll have to try\r
  104. again.\r\n
  105. Nickname: '''
  106. ##################################################
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113. ###################################################
  114. ## The HNCS Class
  115. ###################################################
  116. class HNCS(ThreadingTCPServer):
  117. def verify_request(self, request, client_address):
  118. for key in connections:
  119. if connections[key].client_address[0] == client_address[0]:
  120. if client_address[0] != '127.0.0.1':
  121. return False
  122. return True
  123. def welcome(self):
  124. return '''______________________________________________________
  125. ------------------------------------------------------
  126. %s
  127. ______________________________________________________
  128. ------------------------------------------------------
  129. * Server started %s
  130. * Waiting for connections on port %i
  131. ''' % (gpl, ctime(), PORT)
  132. ##################################################
  133.  
  134.  
  135.  
  136.  
  137.  
  138. ##################################################
  139. ## The Room Class
  140. ##################################################
  141. class Room:
  142. def __init__(self, name, starter):
  143. self.listeners = []
  144. self.name = name
  145. roomlist[self.name] = self
  146. self.listeners.append(starter)
  147. def cleanup(self, connection):
  148. self.listeners.remove(connection)
  149. if len(self.listeners) == 0:
  150. del roomlist[self.name]
  151. def whoHere(self):
  152. container = ''
  153. for listener in self.listeners:
  154. container += listener.__str__()
  155. format = '[ %s ]' % (container)
  156. return endl + format + endl
  157. def listRooms(self):
  158. container = ''
  159. for key in roomlist:
  160. container += (roomlist[key].__str__() + endl)
  161. format = '''\r
  162. -----------------------------------------------------\r
  163. ROOMS\r
  164. -----------------------------------------------------\r\n
  165. %s\r
  166. -----------------------------------------------------\r'''% container
  167. return format
  168. def welcome(self):
  169. return endl + '\t* You are now in :: %s :: *\r\n %s\r\n' % (self.name, self.whoHere())
  170. def __str__(self):
  171. return ':: %s ::\t\t|\t\t%i user(s)' % (self.name, len(self.listeners))
  172.  
  173.  
  174.  
  175. ###################################################
  176. ## The Connection Class
  177. ###################################################
  178. # This is where it all goes down. Upon connection,
  179. # this class automatically runs the self.setup()
  180. # function which sets up a self.username and appends
  181. # a unique instance of the User class to the 'connec-
  182. # tions' list. self.getPress is an infinite loop and
  183. # is where the majority of the action takes place.
  184.  
  185. class Connection(BaseRequestHandler):
  186. def setup(self):
  187. print '[!] %s %s' % (self.client_address[0], ctime())
  188. self.room = 0
  189. self.login()
  190. self.joinRoom('lobby')
  191. print '- %s logged in as "%s"' % (self.client_address[0], self.name)
  192. self.broadcast('\r\n\t* %s connected %s *\r\n' % (self, ctime()))
  193. connections[self.name] = self
  194. self.request.send('You are now logged in as "%s".\r\n' % self.name)
  195. def login(self):
  196. self.request.send(login)
  197. string = self.getString()
  198. while len(string) > maxname or connections.has_key(string):
  199. self.request.send('\r\nSorry, try again: ')
  200. string = self.getString()
  201. if len(string) < maxname:
  202. string = (space * (maxname - len(string))) + string
  203. self.name = string
  204. def handle(self):
  205. sleep(2)
  206. self.request.send(self.welcome()) # send the welcome note
  207. self.getPress() # wait for commands until session is terminated
  208. def finish(self):
  209. self.broadcast('\r\n\t* %s has disconnected *\r\n' % self)
  210. print '[x] %s %s (%s)' % (self.client_address, self.name, ctime(), )
  211. del connections[self.name]
  212. self.leaveRoom()
  213. self.request.close()
  214. def getPress(self):
  215. while True:
  216. try:
  217. press = self.request.recv(packet)
  218. self.request.send('\b ') # keep the cursor from moving
  219. self.request.send('\b') # "
  220. if press in ('?', '?\r\n'): # print the help menu
  221. self.request.send(clientHelp)
  222. elif press in ('w', 'w\r\n'): # print who is online
  223. self.request.send(self.who())
  224. elif press in ('r', 'r\r\n'): # print users in room
  225. self.request.send(self.room.whoHere())
  226. elif press == endl: # go to the message prompt
  227. self.message()
  228. elif press in ('c', 'c\r\n'): # clear the screen (kind of a primative way, eh?)
  229. self.request.send(endl * 100)
  230. elif press in ('i', 'i\r\n'): # print the info string
  231. self.request.send(info)
  232. elif press in ('j', 'j\r\n'):
  233. self.changeRoom()
  234. elif press in ('l', 'l\r\n'):
  235. self.request.send(self.room.listRooms())
  236. elif press in ('q', 'q\r\n'): # leave the loop and terminate the session
  237. break
  238. else:
  239. self.request.send('\r\n\t* Dude, no. Type ? for'
  240. ' a list of commands. *\r\n')
  241. except:
  242. break
  243. def getString(self):
  244. string = ''
  245. keypress = []
  246. press = self.request.recv(packet) # get a keypress
  247. if len(press) <= 1: # IF CLIENT IS IN CHAR MODE... (WINDOWS)
  248. while press != endl: # while user isn't finished,
  249. if press == '\b': # if it was a backspace,
  250. if (len(keypress) > 0): # and the keypress array isn't empty,
  251. self.request.send(' \b') # send a coverup so it looks like a backspace
  252. keypress.pop() # and remove last char
  253. else: # if array is empty
  254. while press == '\b': # while still pressing backspace
  255. self.request.send(' ') # send blank
  256. press = self.request.recv(packet) # get and test a new press
  257. if press == endl: break
  258. keypress.append(press)
  259. else:
  260. keypress.append(press) # if it wasn't a backspace, append it to array
  261. press = self.request.recv(packet) # get a new press
  262. for key in keypress: # for each key held in keypress
  263. string += key # add it to the string
  264.  
  265. else: # IF THE CLIENT IS IN LINE MODE (*NIX),
  266. string = press # the press is the string.
  267. if endl in string: # if an end-of-line is in the string,
  268. string = string.strip(endl) # remove it.
  269. return string # return the string
  270. def message(self):
  271. self.request.send('> %s: ' % self.name)
  272. string = self.getString()
  273. if len(string) == 0:
  274. self.request.send('\t<no message sent>\r\n')
  275. else:
  276. msg = '\r\n> %s: %s\r\n' % (self.name, string)
  277. self.roomcast(msg)
  278. def broadcast(self, data):
  279. for key in connections:
  280. if connections[key] != self:
  281. connections[key].request.send(data)
  282. def roomcast(self, data):
  283. for listener in self.room.listeners:
  284. if listener != self:
  285. listener.request.send(data)
  286. def leaveRoom(self):
  287. if self.room:
  288. self.room.cleanup(self)
  289. def changeRoom(self):
  290. self.request.send('\r\njoin room: ')
  291. string = self.getString()
  292. if len(string) == 0:
  293. self.request.send('\t<aborted>\r\n')
  294. else:
  295. self.joinRoom(string)
  296. def joinRoom(self, roomname):
  297. if self.room:
  298. if self.room.name == roomname:
  299. self.request.send('\r\n\t* You are already in ::%s:: *\r\n' % self.room.name)
  300. else:
  301. self.room.cleanup(self)
  302. if roomlist.has_key(roomname):
  303. self.room = roomlist[roomname]
  304. self.room.listeners.append(self)
  305. self.request.send(self.room.welcome())
  306. else:
  307. self.room = Room(roomname, self)
  308. self.request.send(self.room.welcome())
  309. else:
  310. if roomlist.has_key(roomname):
  311. self.room = roomlist[roomname]
  312. self.room.listeners.append(self)
  313. else:
  314. self.room = Room(roomname, self)
  315. def who(self):
  316. container = ''
  317. for user in connections:
  318. container += user.__str__()
  319. format = '[%s]' % container
  320. return endl + format + endl
  321. def welcome(self):
  322. return '''\r\n
  323. %s
  324. _______________________________________________________\r
  325. -------------------------------------------------------\r
  326. %s\r
  327. \t\tType '?' for help.\r
  328. _______________________________________________________\r
  329. -------------------------------------------------------\r
  330. Local time is %s\r
  331. %s
  332. ''' % (gpl, artwork, ctime(), self.room.welcome())
  333.  
  334.  
  335. def __str__(self):
  336. return ' %s ' % self.name
  337. ###################################################
  338.  
  339. server = HNCS(ADDRESS, Connection)
  340.  
  341. if __name__ == '__main__':
  342. print server.welcome()
  343. server.serve_forever()
Reply With Quote Quick reply to this message  
Join Date: Jul 2005
Posts: 1,221
Reputation: bumsfeld will become famous soon enough bumsfeld will become famous soon enough 
Solved Threads: 137
bumsfeld's Avatar
bumsfeld bumsfeld is offline Offline
Nearly a Posting Virtuoso

Re: Python Chat Server

 
0
  #2
May 17th, 2007
Interesting project! I am working myself though the code. I have never written anyhing like that.
Reply With Quote Quick reply to this message  
Join Date: Mar 2008
Posts: 3
Reputation: GreyInTheLaw is an unknown quantity at this point 
Solved Threads: 0
GreyInTheLaw GreyInTheLaw is offline Offline
Newbie Poster

Re: Python Chat Server

 
0
  #3
Mar 2nd, 2008
Oh! This is interesting.
I've just ran the code and connected a couple of clients.
This is actually good.

To be honest I would have a functional use for this. Not only am I learning python myself but I was also looking for an ultra-simple chat program to run on my network. My network incorporates a lot of different OS and some systems don't have GUIs, or other 'standard' features like that and I was looking for a chat program that can run on all systems with as little effort as possible,

I think I can learn from this as well as have a functional use. Glad I read this post!
I hope you don't mind if I have a play around with this and see what I can make it do =]
Reply With Quote Quick reply to this message  
Join Date: Dec 2008
Posts: 1
Reputation: Briix is an unknown quantity at this point 
Solved Threads: 0
Briix Briix is offline Offline
Newbie Poster

Re: Python Chat Server

 
0
  #4
Dec 28th, 2008
This looks pretty cool.
I must admit that I'm a noob when it comes to Python programming, but, I'm just wondering how I connect to the server, because when I run the python file it just says: Waiting for connections on port 65438.

How do I connect and start writing ?
Reply With Quote Quick reply to this message  
Join Date: Jun 2007
Posts: 1,357
Reputation: evstevemd has a spectacular aura about evstevemd has a spectacular aura about evstevemd has a spectacular aura about 
Solved Threads: 127
evstevemd's Avatar
evstevemd evstevemd is offline Offline
Nearly a Posting Virtuoso

Re: Python Chat Server

 
0
  #5
Dec 29th, 2008
Have played around with some things and here is one which was in my to-do-list
Great! I will see it when I finish current exercise
Thanks sir!!
Atheist: God is man made imagination, he doesn't exist!
Theist: It's okay, can you imagine anything else that doesn't exist?
Junior MD --- Python, C++ and PHP
Reply With Quote Quick reply to this message  
Join Date: Jun 2007
Posts: 1,357
Reputation: evstevemd has a spectacular aura about evstevemd has a spectacular aura about evstevemd has a spectacular aura about 
Solved Threads: 127
evstevemd's Avatar
evstevemd evstevemd is offline Offline
Nearly a Posting Virtuoso

Re: Python Chat Server

 
0
  #6
Dec 29th, 2008
It waits forever for a port!
Atheist: God is man made imagination, he doesn't exist!
Theist: It's okay, can you imagine anything else that doesn't exist?
Junior MD --- Python, C++ and PHP
Reply With Quote Quick reply to this message  
Reply

This thread is more than three months old.
Perhaps start a new thread instead?
Message:



Similar Threads
Other Threads in the Python Forum
Thread Tools Search this Thread



About Us | Contact Us | Advertise | DaniWeb | Acceptable Use Policy | RSS Feed

©2003 - 2009 DaniWeb® LLC