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
36c82552
Commit
36c82552
authored
Mar 10, 2011
by
Sander Mathijs van Veen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Telematica: Almost finished client and server.
parent
bb7db307
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
77 additions
and
19 deletions
+77
-19
telematica/ass1/async.py
telematica/ass1/async.py
+6
-4
telematica/ass1/server.py
telematica/ass1/server.py
+71
-15
No files found.
telematica/ass1/async.py
View file @
36c82552
...
...
@@ -77,6 +77,7 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
elif
chunk
==
'
\
n
'
and
buf
[
-
1
]
==
'
\
r
'
:
if
not
multi_line
:
break
self
.
debug_log
(
'receiving multi line response...'
)
if
buf
[
-
3
:]
==
'
\
r
\
n
\
r
'
:
# Remove trailing '\n\r' from multi line response
buf
=
buf
[:
-
2
]
...
...
@@ -84,7 +85,7 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
buf
+=
chunk
buf
=
buf
[:
-
1
]
self
.
debug_log
(
'< %s'
%
buf
)
self
.
debug_log
(
'< %s'
%
buf
.
replace
(
'
\
n
'
,
'
\
\
n'
).
replace
(
'
\
r
'
,
'
\
\
r'
)
)
# Invoke the proper callback function.
if
not
self
.
verified
:
...
...
@@ -118,7 +119,7 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
if
not
self
.
authentification_sent
:
self
.
send_queue
.
put
(
'USER %s'
%
self
.
user
)
self
.
authentification_sent
=
True
elif
buf
[
1
:
9
]
==
'Username
'
:
elif
buf
[
0
]
==
'+
'
:
# TODO: handle 'username is taken'.
self
.
authenticated
=
True
if
'authenticated'
in
self
.
event_list
:
...
...
@@ -130,8 +131,9 @@ class ClientConnection(object, AsyncBase, asyncore.dispatcher):
# After authentification, fetch the list of users currently logged in.
if
not
self
.
retrieved_user_list
:
if
not
self
.
request_user_list_sent
:
self
.
request_user_list_sent
=
True
self
.
retrieve_users
()
#self.request_user_list_sent = True
#self.retrieve_users()
pass
else
:
# TODO: process user list
self
.
retrieved_user_list
=
True
...
...
telematica/ass1/server.py
View file @
36c82552
...
...
@@ -10,8 +10,10 @@ import sys
from
asyncbase
import
AsyncBase
# Greeting message sent to a connected client.
GREETING_MSG
=
'Hi there!'
# Major and minor version of this server.
MAJOR_VERSION
=
1
MINOR_VERSION
=
0
...
...
@@ -34,14 +36,13 @@ class Server(asyncore.dispatcher):
self
.
port
=
port
self
.
handler
=
handler
self
.
create_socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
logging
.
config
.
fileConfig
(
'logging.conf'
)
self
.
log
=
logging
.
getLogger
(
'Server'
)
# Listen on given ip-address and port
self
.
create_socket
(
socket
.
AF_INET
,
socket
.
SOCK_STREAM
)
self
.
set_reuse_addr
()
self
.
bind
((
ip
,
port
))
self
.
log
.
info
(
'waiting for incoming connections on port %s.'
%
port
)
self
.
listen
(
5
)
...
...
@@ -56,27 +57,54 @@ class Server(asyncore.dispatcher):
try
:
conn
,
addr
=
self
.
accept
()
self
.
log
.
info
(
'accepted client %s:%d'
%
addr
)
client
=
self
.
connect_client
(
addr
)
client
=
self
.
connect_client
(
conn
,
addr
)
except
socket
.
error
:
self
.
log
.
warning
(
'warning: server accept() threw an exception.'
)
return
except
TypeError
:
self
.
log
.
warning
(
'warning: server accept() threw EWOULDBLOCK.'
)
return
def
connect_client
(
self
,
conn
,
addr
):
"""
Initialise a client connection after the server accepted an incoming
connection. This will set the connection handler.
"""
client
=
ClientData
()
# creates an instance of the handler class to handle the
# request/response on the incoming connection.
self
.
handler
(
conn
,
addr
,
client
,
self
)
def
connect_client
(
self
,
addr
):
self
.
clients
[
'%s:%d'
%
addr
]
=
ClientData
()
return
self
.
clients
[
'%s:%d'
%
addr
]
client
.
handler
=
self
.
handler
(
conn
,
addr
,
client
,
self
)
client
.
username
=
''
self
.
clients
[
'%s:%d'
%
addr
]
=
client
return
client
def
disconnect_client
(
self
,
addr
):
"""
Client leaves the chat server. This function is called when the socket
is broken or the client closes the connection gracefully.
"""
# Suppress error if a client is already disconnected.
try
:
client
=
self
.
clients
[
'%s:%d'
%
addr
]
self
.
send_all
(
'LEAVE %s'
%
client
.
username
,
True
)
del
self
.
clients
[
'%s:%d'
%
addr
]
except
KeyError
:
pass
def
change_username
(
self
,
addr
,
username
):
"""
Update the username of the client.
"""
self
.
clients
[
'%s:%d'
%
addr
].
username
=
username
# TODO: notify other clients of changed username
def
send_all
(
self
,
msg
,
sender
=
None
):
"""
Send a message or notification from a client to all connected clients
(optionally including to the sender).
"""
for
c
in
self
.
clients
:
if
self
.
clients
[
c
].
handler
!=
sender
:
self
.
clients
[
c
].
handler
.
send_raw
(
msg
)
class
RequestHandler
(
AsyncBase
,
asyncore
.
dispatcher
):
def
__init__
(
self
,
conn
,
address
,
client
,
server
):
...
...
@@ -86,18 +114,25 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
self
.
address
=
address
self
.
client
=
client
self
.
server
=
server
self
.
username
=
''
self
.
log
=
self
.
server
.
log
self
.
send_welcome_message
()
def
send_welcome_message
(
self
):
"""
Welcome our new client by sending a welcome message. This message
contains the server version number and a greetings message.
"""
self
.
send_raw
(
"CHAT/%d.%d/%s"
\
%
(
MAJOR_VERSION
,
MINOR_VERSION
,
GREETING_MSG
))
def
handle_read
(
self
):
"""
Receive a message from the client. If the connection is somehow broken,
disconnect the client and clean the corresponding data.
"""
buf
=
''
# Receive a message from the client. If the connection is somehow
# broken, disconnect the client and clean the corresponding data.
try
:
while
True
:
chunk
=
self
.
recv
(
1
)
...
...
@@ -115,10 +150,11 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
# Received a message, so it's time to parse the message.
buf
=
buf
[:
-
1
]
self
.
debug_log
(
'< %s'
%
buf
)
self
.
parse_response
(
buf
)
def
handle_error
(
self
):
self
.
server
.
disconnect_client
(
self
.
address
)
def
parse_response
(
self
,
buf
):
"""
>>> class DummyServer(object):
...
...
@@ -140,9 +176,24 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
if
cmd
==
'USER'
:
# User changes/sets its username.
if
re
.
match
(
ur'^[^\u0000-\u001f\u007f-\u009f/:]+$'
,
buf
[
5
:]):
if
not
self
.
username
:
self
.
send_all
(
'JOIN %s'
%
buf
[
5
:],
True
)
else
:
self
.
send_all
(
'RENAME %s/%s'
\
%
(
self
.
username
,
buf
[
5
:]),
True
)
self
.
set_username
(
buf
[
5
:])
return
self
.
send_positive
(
'Ok'
)
return
self
.
send_negative
(
'Invalid username.'
)
# TODO: user can't send a message if he didn't send his username first.
if
cmd
==
'SAY'
:
return
self
.
send_all
(
'SAY %s/%s'
%
(
self
.
username
,
buf
[
4
:]))
if
cmd
==
'NAMES'
:
self
.
send_raw
(
'+Ok:'
)
for
c
in
self
.
server
.
clients
:
self
.
send_raw
(
self
.
server
.
clients
[
c
].
username
)
self
.
send_raw
(
''
)
return
True
return
self
.
send_negative
(
'Unsupported command.'
)
def
send_positive
(
self
,
msg
):
...
...
@@ -153,7 +204,12 @@ class RequestHandler(AsyncBase, asyncore.dispatcher):
self
.
send_raw
(
'-%s'
%
msg
)
return
False
def
send_all
(
self
,
msg
,
except_sender
=
False
):
self
.
server
.
send_all
(
msg
,
except_sender
and
self
)
return
True
def
set_username
(
self
,
username
):
self
.
username
=
username
self
.
server
.
change_username
(
self
.
address
,
username
)
if
__name__
==
'__main__'
:
...
...
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