Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
U
uva
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Taddeüs Kroes
uva
Commits
49248d15
Commit
49248d15
authored
Mar 11, 2011
by
Sander Mathijs van Veen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Telematica: minor bug fixes.
parent
10ebfad0
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
48 additions
and
15 deletions
+48
-15
telematica/ass1/async.py
telematica/ass1/async.py
+3
-4
telematica/ass1/doc/implementation.rst
telematica/ass1/doc/implementation.rst
+15
-2
telematica/ass1/server.py
telematica/ass1/server.py
+30
-9
No files found.
telematica/ass1/async.py
View file @
49248d15
...
@@ -110,9 +110,8 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
...
@@ -110,9 +110,8 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
try
:
try
:
chunk
=
self
.
recv
(
1
)
chunk
=
self
.
recv
(
1
)
except
socket
.
error
,
e
:
except
socket
.
error
,
e
:
#
Suppress
"Resource temporarily unavailable" exceptions.
#
Handle
"Resource temporarily unavailable" exceptions.
if
e
.
errno
==
EAGAIN
:
if
e
.
errno
==
EAGAIN
:
# Wait 5 ms
import
time
import
time
time
.
sleep
(
0.005
)
time
.
sleep
(
0.005
)
continue
continue
...
@@ -207,7 +206,7 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
...
@@ -207,7 +206,7 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
Helper function used to parse the server notifications. This way,
Helper function used to parse the server notifications. This way,
message parsing is separated from the notification logic.
message parsing is separated from the notification logic.
"""
"""
match
=
re
.
match
(
'^SAY ([^
\
r
\
n
:/]+)/(.
+)'
,
buf
)
match
=
re
.
match
(
'^SAY ([^
\
x00
-
\
x1F
:/]+)/([^
\
x00
-
\
x1F
]
+)'
,
buf
)
if
match
:
if
match
:
if
'message'
in
self
.
event_list
:
if
'message'
in
self
.
event_list
:
self
.
event_list
[
'message'
](
self
,
match
.
group
(
1
),
match
.
group
(
2
))
self
.
event_list
[
'message'
](
self
,
match
.
group
(
1
),
match
.
group
(
2
))
...
...
telematica/ass1/doc/implementation.rst
View file @
49248d15
...
@@ -32,7 +32,8 @@ Since some functionality of the chat connection is used in both the client and
...
@@ -32,7 +32,8 @@ Since some functionality of the chat connection is used in both the client and
server, it is wise to create a base class containing those methods: *AsyncBase*.
server, it is wise to create a base class containing those methods: *AsyncBase*.
We used the *asyncore.dispatcher* class (part of the python standard library) to
We used the *asyncore.dispatcher* class (part of the python standard library) to
create a nice abstraction layer on top of the socket. The abstraction layer is
create a nice abstraction layer on top of the socket. The abstraction layer is
event-oriented and provides various event callback functions:
event-oriented and provides the following event callback functions (among some
other less relevant ones):
1. **handle_write**.
1. **handle_write**.
...
@@ -76,6 +77,12 @@ connection does take messages from the queue, if its local message buffer is
...
@@ -76,6 +77,12 @@ connection does take messages from the queue, if its local message buffer is
empty (which means all its data is sent to the server or the connection is
empty (which means all its data is sent to the server or the connection is
just initialised).
just initialised).
The protocol uses the Backus-Naur form and therefore, we chose regular
expressions to validate incoming messages from the server. Regexes are easier to
maintain than handwritten parsers, since they allow you to check for certain
ranges of characters (for example, the control character range is
**[\\x00-\\x1F]**).
Text-based interface (using curses)
Text-based interface (using curses)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
@@ -191,5 +198,11 @@ We implemented the following commands:
...
@@ -191,5 +198,11 @@ We implemented the following commands:
Server side
Server side
----------
----------
Foo
Multiple client handling
~~~~~~~~~~~~~~~~~~~~~~~~
The class *Server* accepts the incoming connections from clients and initialises
a request handler (see class *RequestHandler*) for each accepted connection. The
servers logs all its information, warnings and errors to stdout. To change the
behaviour of the server log, alter the configuration file *logging.conf*.
telematica/ass1/server.py
View file @
49248d15
...
@@ -32,6 +32,9 @@ class Server(asyncore.dispatcher):
...
@@ -32,6 +32,9 @@ class Server(asyncore.dispatcher):
self
.
port
=
port
self
.
port
=
port
self
.
handler
=
handler
self
.
handler
=
handler
# Dictonary which maps ip/port tuple to client data object.
self
.
clients
=
{}
logging
.
config
.
fileConfig
(
'logging.conf'
)
logging
.
config
.
fileConfig
(
'logging.conf'
)
self
.
log
=
logging
.
getLogger
(
'Server'
)
self
.
log
=
logging
.
getLogger
(
'Server'
)
...
@@ -42,9 +45,6 @@ class Server(asyncore.dispatcher):
...
@@ -42,9 +45,6 @@ class Server(asyncore.dispatcher):
self
.
log
.
info
(
'waiting for incoming connections on port %s.'
%
port
)
self
.
log
.
info
(
'waiting for incoming connections on port %s.'
%
port
)
self
.
listen
(
5
)
self
.
listen
(
5
)
# Dictonary which maps ip/port tuple to client data object.
self
.
clients
=
{}
def
handle_accept
(
self
):
def
handle_accept
(
self
):
"""
"""
Handle the incoming connection's request.
Handle the incoming connection's request.
...
@@ -149,12 +149,27 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
...
@@ -149,12 +149,27 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
self
.
parse_response
(
buf
)
self
.
parse_response
(
buf
)
def
handle_error
(
self
):
def
handle_error
(
self
):
import
sys
t
,
v
,
tb
=
sys
.
exc_info
()
tbinfo
=
[]
while
tb
:
tbinfo
.
append
((
tb
.
tb_frame
.
f_code
.
co_filename
,
tb
.
tb_frame
.
f_code
.
co_name
,
str
(
tb
.
tb_lineno
)
))
tb
=
tb
.
tb_next
file
,
function
,
line
=
tbinfo
[
-
1
]
self
.
log
.
error
(
'%s raised "%s" in %s:%s'
\
%
(
str
(
v
),
function
,
file
,
line
))
self
.
log
.
error
(
' '
.
join
([
'[%s|%s|%s]'
%
x
for
x
in
tbinfo
]))
self
.
server
.
disconnect_client
(
self
.
address
)
self
.
server
.
disconnect_client
(
self
.
address
)
def
parse_response
(
self
,
buf
):
def
parse_response
(
self
,
buf
):
"""
"""
>>> class DummyServer(object):
>>> class DummyServer(object):
... def __init__(self): self.log = None
... def __init__(self): self.log = None
; self.clients = {}
... def change_username(self, addr, username): pass
... def change_username(self, addr, username): pass
... def send_all(self, msg, sender): pass
... def send_all(self, msg, sender): pass
>>> req = RequestHandler(None, None, None, DummyServer())
>>> req = RequestHandler(None, None, None, DummyServer())
...
@@ -171,14 +186,20 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
...
@@ -171,14 +186,20 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
# Client wants to chat.
# Client wants to chat.
return
self
.
send_positive
(
'Ok'
)
return
self
.
send_positive
(
'Ok'
)
if
cmd
==
'USER'
:
if
cmd
==
'USER'
:
# User changes/sets its username.
# User changes/sets its username. Make sure the username is not
if
re
.
match
(
ur'^[^\u0000-\u001f\u007f-\u009f/:]+$'
,
buf
[
5
:]):
# already taken. If the name is valid, notify the other clients.
name
=
buf
[
5
:]
for
c
in
self
.
server
.
clients
:
if
self
.
server
.
clients
[
c
].
username
==
name
\
and
self
.
server
.
clients
[
c
].
handler
!=
self
:
return
self
.
send_negative
(
'Username already taken.'
)
if
re
.
match
(
ur'^[^\u0000-\u001f\u007f-\u009f/:]+$'
,
name
):
if
not
self
.
username
:
if
not
self
.
username
:
self
.
send_all
(
'JOIN %s'
%
buf
[
5
:]
,
True
)
self
.
send_all
(
'JOIN %s'
%
name
,
True
)
else
:
else
:
self
.
send_all
(
'RENAME %s/%s'
\
self
.
send_all
(
'RENAME %s/%s'
\
%
(
self
.
username
,
buf
[
5
:]
),
True
)
%
(
self
.
username
,
name
),
True
)
self
.
set_username
(
buf
[
5
:]
)
self
.
set_username
(
name
)
return
self
.
send_positive
(
'Ok'
)
return
self
.
send_positive
(
'Ok'
)
return
self
.
send_negative
(
'Invalid username.'
)
return
self
.
send_negative
(
'Invalid username.'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment