Lab3 - shared whiteboard

From Inforail
Jump to: navigation, search

Keywords

client, server, UDP, BSD sockets, protocol, whiteboard, broadcast

Objectives

Familiarize yourself with UDP, learn how to send and receive datagrams. Understand the difference between TCP and UDP. Use UDP's broadcasting feature.

Overview

  • Create a shared whiteboard tool which enables several people to collaborate in real-time, by drawing sketches on a canvas.
  • Every person draws with their own colour, by clicking on the canvas.
  • The stroke will be rendered on the screens of all the participants (except that of the author - which already displays the image).
  • Devise the protocol that your tool uses and provide a formal description.

Generic requirements

  • The program must rely on the BSD sockets API, not some other library which is an abstraction on top of BSD sockets.
  • You are free to use whatever graphical library you prefer. To facilitate the development process, check out the helloworldian Tkinter sample included in the assignment.


Grading policy

Assuming that everything works right,

  • 7 - for creating and documenting the protocol that provides the features below (i.e. you don't need to implement any feature, just write the specs)
  • 8 - the strokes generated on the server are displayed on all the clients;
  • 9 - each client is also a server, thus people can draw simultaneously, such that everyone can see the same thing on their screen;
  • 10 - for implementing these features:
    • reset - clears the participants' screens
      • if at least 2 participants agree to reset the canvas
    • custom colour for each participant's stroke
      • colours must not collide


A partially implemented feature that does not work 100% right may still be accepted as fully implemented, provided that your report describes the nature of the problem and provides some guesses about what the solution is supposed to be.

Implementation recommendations

  • Perhaps it is a good idea to use UDP for some functionality, while other features can be based on TCP


References


Tkinter canvas drawing skeleton

This example program uses Tkinter's canvas to draw on the screen. Tkinter is shipped with Python, this example should work out of the box. It features:

  • binding to certain events
    • mouse click
    • move mouse while a button is clicked
    • custom event, in case you need it
  • another thread which can update the canvas

Warning - this code is not perfect, it is here only to give you a basic idea of how Tkinter works, such that you can focus on the network programming and designing your protocol, rather than tinkering with user interfaces.

from Tkinter import *
from Tkinter import Tk
import time
import threading
import random


lastx, lasty = 0, 0
canvasWidth = 300
canvasHeight = 300

def doFoo(*args):
    print "Virtual event was generated"

def xy(event):
    global lastx, lasty
    lastx, lasty = event.x, event.y

def addLine(event):
    global lastx, lasty
    canvas.create_line((lastx, lasty, event.x, event.y))
    lastx, lasty = event.x, event.y

def dot(canvas, x, y):
	canvas.create_oval(x, y, x+1, y+1)


def worker(root, canvas):
	"""
	This function should read something from the socket and
	plot the dot on the canvas if a message is received.
	"""
	while True:
		time.sleep(2)
		#the coordinates of the dot to be drawn are randomized
		#but normally you should get them off the network
		x = random.randint(0, canvasWidth)
		y = random.randint(0, canvasHeight)
		dot(canvas, x, y)
		
		#in case you wish to do something else, you can
		#generate your custom event here
		#root.event_generate("<<Foo>>",when="tail")	


if __name__ == "__main__":
	root = Tk()
	root.columnconfigure(0, weight=1)
	root.rowconfigure(0, weight=1)
	root.bind("<<Foo>>",doFoo) #event, custom (not tied to the mouse/keyboard)

	canvas = Canvas(root, width=canvasWidth, height=canvasHeight)
	canvas.grid(column=0, row=0, sticky=(N, W, E, S))
	canvas.bind("<Button-1>", xy) #event, mouse-click
	canvas.bind("<B1-Motion>", addLine) #event, move mouse with a clicked button

	#start another thread, it will read stuff from the socket
	#and update the canvas if needed
	t = threading.Thread(target=worker, args=(root, canvas) )
	t.start()
	
	#drawing the canvas itself
	root.mainloop()