Initial revision
diff --git a/Demo/sockets/README b/Demo/sockets/README
new file mode 100644
index 0000000..463ab1c
--- /dev/null
+++ b/Demo/sockets/README
@@ -0,0 +1,7 @@
+Contents of this directory:
+
+echosvr.py		About the simplest TCP server possible.
+finger.py		Client for the 'finger' protocol.
+telnet.py		Client for the 'telnet' protocol.
+throughput.py		Client and server to measure TCP throughput.
+udpecho.py		Client and server for the UDP echo protocol.
diff --git a/Demo/sockets/echosvr.py b/Demo/sockets/echosvr.py
new file mode 100755
index 0000000..f245583
--- /dev/null
+++ b/Demo/sockets/echosvr.py
@@ -0,0 +1,31 @@
+#! /usr/local/python
+
+# Python implementation of an 'echo' tcp server: echo all data it receives.
+#
+# This is the simplest possible server, sevicing a single request only.
+
+import sys
+from socket import *
+
+# The standard echo port isn't very useful, it requires root permissions!
+# ECHO_PORT = 7
+ECHO_PORT = 50000 + 7
+BUFSIZE = 1024
+
+def main():
+	if len(sys.argv) > 1:
+		port = int(eval(sys.argv[1]))
+	else:
+		port = ECHO_PORT
+	s = socket(AF_INET, SOCK_STREAM)
+	s.bind('', port)
+	s.listen(0)
+	conn, (host, remoteport) = s.accept()
+	print 'connected by', host, remoteport
+	while 1:
+		data = conn.recv(BUFSIZE)
+		if not data:
+			break
+		conn.send(data)
+
+main()
diff --git a/Demo/sockets/finger.py b/Demo/sockets/finger.py
new file mode 100755
index 0000000..8aa0535
--- /dev/null
+++ b/Demo/sockets/finger.py
@@ -0,0 +1,58 @@
+#! /usr/local/python
+
+# Python interface to the Internet finger daemon.
+#
+# Usage: finger [options] [user][@host] ...
+#
+# If no host is given, the finger daemon on the local host is contacted.
+# Options are passed uninterpreted to the finger daemon!
+
+
+import sys, string
+from socket import *
+
+
+# Hardcode the number of the finger port here.
+# It's not likely to change soon...
+#
+FINGER_PORT = 79
+
+
+# Function to do one remote finger invocation.
+# Output goes directly to stdout (although this can be changed).
+#
+def finger(host, args):
+	s = socket(AF_INET, SOCK_STREAM)
+	s.connect(host, FINGER_PORT)
+	s.send(args + '\n')
+	while 1:
+		buf = s.recv(1024)
+		if not buf: break
+		sys.stdout.write(buf)
+	sys.stdout.flush()
+
+
+# Main function: argument parsing.
+#
+def main():
+	options = ''
+	i = 1
+	while i < len(sys.argv) and sys.argv[i][:1] = '-':
+		options = options + sys.argv[i] + ' '
+		i = i+1
+	args = sys.argv[i:]
+	if not args:
+		args = ['']
+	for arg in args:
+		if '@' in arg:
+			at = string.index(arg, '@')
+			host = arg[at+1:]
+			arg = arg[:at]
+		else:
+			host = ''
+		finger(host, options + arg)
+
+
+# Call the main function.
+#
+main()
diff --git a/Demo/sockets/telnet.py b/Demo/sockets/telnet.py
new file mode 100755
index 0000000..60f832a
--- /dev/null
+++ b/Demo/sockets/telnet.py
@@ -0,0 +1,109 @@
+#! /usr/local/python
+
+# Minimal interface to the Internet telnet protocol.
+#
+# It refuses all telnet options and does not recognize any of the other
+# telnet commands, but can still be used to connect in line-by-line mode.
+# It's also useful to play with a number of other services,
+# like time, finger, smtp and even ftp.
+#
+# Usage: telnet host [port]
+#
+# The port may be a service name or a decimal port number;
+# it defaults to 'telnet'.
+
+
+import sys, posix, time
+from socket import *
+
+BUFSIZE = 1024
+
+# Telnet protocol characters
+
+IAC  = chr(255)	# Interpret as command
+DONT = chr(254)
+DO   = chr(253)
+WONT = chr(252)
+WILL = chr(251)
+
+def main():
+	host = sys.argv[1]
+	try:
+		hostaddr = gethostbyname(host)
+	except error:
+		sys.stderr.write(sys.argv[1] + ': bad host name\n')
+		sys.exit(2)
+	#
+	if len(sys.argv) > 2:
+		servname = sys.argv[2]
+	else:
+		servname = 'telnet'
+	#
+	if '0' <= servname[:1] <= '9':
+		port = eval(servname)
+	else:
+		try:
+			port = getservbyname(servname, 'tcp')
+		except error:
+			sys.stderr.write(servname + ': bad tcp service name\n')
+			sys.exit(2)
+	#
+	s = socket(AF_INET, SOCK_STREAM)
+	#
+	try:
+		s.connect(host, port)
+	except error, msg:
+		sys.stderr.write('connect failed: ' + `msg` + '\n')
+		sys.exit(1)
+	#
+	pid = posix.fork()
+	#
+	if pid = 0:
+		# child -- read stdin, write socket
+		while 1:
+			line = sys.stdin.readline()
+			s.send(line)
+	else:
+		# parent -- read socket, write stdout
+		iac = 0		# Interpret next char as command
+		opt = ''	# Interpret next char as option
+		while 1:
+			data = s.recv(BUFSIZE)
+			if not data:
+				# EOF; kill child and exit
+				sys.stderr.write( '(Closed by remote host)\n')
+				posix.kill(pid, 9)
+				sys.exit(1)
+			cleandata = ''
+			for c in data:
+				if opt:
+					print ord(c)
+					s.send(opt + c)
+					opt = ''
+				elif iac:
+					iac = 0
+					if c = IAC:
+						cleandata = cleandata + c
+					elif c in (DO, DONT):
+						if c = DO: print '(DO)',
+						else: print '(DONT)',
+						opt = IAC + WONT
+					elif c in (WILL, WONT):
+						if c = WILL: print '(WILL)',
+						else: print '(WONT)',
+						opt = IAC + DONT
+					else:
+						print '(command)', ord(c)
+				elif c = IAC:
+					iac = 1
+					print '(IAC)',
+				else:
+					cleandata = cleandata + c
+			sys.stdout.write(cleandata)
+			sys.stdout.flush()
+
+
+try:
+	main()
+except KeyboardInterrupt:
+	pass
diff --git a/Demo/sockets/throughput.py b/Demo/sockets/throughput.py
new file mode 100755
index 0000000..411af9f
--- /dev/null
+++ b/Demo/sockets/throughput.py
@@ -0,0 +1,93 @@
+#! /usr/local/python
+
+# Test network throughput.
+#
+# Usage:
+# 1) on host_A: throughput -s [port]			# start a server
+# 2) on host_B: throughput -c  count host_A [port]	# start a client
+#
+# The server will service multiple clients until it is killed.
+#
+# The client performs one transfer of count*BUFSIZE bytes and
+# measures the time it takes (roundtrip!).
+
+
+import sys, time
+from socket import *
+
+MY_PORT = 50000 + 42
+
+BUFSIZE = 1024
+
+
+def main():
+	if len(sys.argv) < 2:
+		usage()
+	if sys.argv[1] = '-s':
+		server()
+	elif sys.argv[1] = '-c':
+		client()
+	else:
+		usage()
+
+
+def usage():
+	sys.stdout = sys.stderr
+	print 'Usage:    (on host_A) throughput -s [port]'
+	print 'and then: (on host_B) throughput -c count host_A [port]'
+	sys.exit(2)
+
+
+def server():
+	if len(sys.argv) > 2:
+		port = eval(sys.argv[2])
+	else:
+		port = MY_PORT
+	s = socket(AF_INET, SOCK_STREAM)
+	s.bind('', port)
+	s.listen(0)
+	print 'Server ready...'
+	while 1:
+		conn, (host, remoteport) = s.accept()
+		while 1:
+			data = conn.recv(BUFSIZE)
+			if not data:
+				break
+			del data
+		conn.send('OK\n')
+		conn.close()
+		print 'Done with', host, 'port', remoteport
+
+
+def client():
+	if len(sys.argv) < 4:
+		usage()
+	count = int(eval(sys.argv[2]))
+	host = sys.argv[3]
+	if len(sys.argv) > 4:
+		port = eval(sys.argv[4])
+	else:
+		port = MY_PORT
+	testdata = 'x' * (BUFSIZE-1) + '\n'
+	t1 = time.millitimer()
+	s = socket(AF_INET, SOCK_STREAM)
+	t2 = time.millitimer()
+	s.connect(host, port)
+	t3 = time.millitimer()
+	i = 0
+	while i < count:
+		i = i+1
+		s.send(testdata)
+	s.shutdown(1) # Send EOF
+	t4 = time.millitimer()
+	data = s.recv(BUFSIZE)
+	t5 = time.millitimer()
+	print data
+	print 'Raw timers:', t1, t2, t3, t4, t5
+	print 'Intervals:', t2-t1, t3-t2, t4-t3, t5-t4
+	print 'Total:', t5-t1
+	print 'Throughput:', int(float(BUFSIZE*count) / float(t5-t1)),
+	print 'K/sec.'
+
+
+main()
diff --git a/Demo/sockets/udpecho.py b/Demo/sockets/udpecho.py
new file mode 100755
index 0000000..53dff64
--- /dev/null
+++ b/Demo/sockets/udpecho.py
@@ -0,0 +1,63 @@
+#! /usr/local/python
+
+# Client and server for udp (datagram) echo.
+#
+# Usage: udpecho -s [port]            (to start a server)
+# or:    udpecho -c host [port] <file (client)
+
+import sys
+from socket import *
+
+ECHO_PORT = 50000 + 7
+BUFSIZE = 1024
+
+def main():
+	if len(sys.argv) < 2:
+		usage()
+	if sys.argv[1] = '-s':
+		server()
+	elif sys.argv[1] = '-c':
+		client()
+	else:
+		usage()
+
+def usage():
+	sys.stdout = sys.stderr
+	print 'Usage: udpecho -s [port]            (server)'
+	print 'or:    udpecho -c host [port] <file (client)'
+	sys.exit(2)
+
+def server():
+	if len(sys.argv) > 2:
+		port = eval(sys.argv[2])
+	else:
+		port = ECHO_PORT
+	s = socket(AF_INET, SOCK_DGRAM)
+	s.bind('', port)
+	print 'udp echo server ready'
+	while 1:
+		data, addr = s.recvfrom(BUFSIZE)
+		print 'server received', `data`, 'from', `addr`
+		s.sendto(data, addr)
+
+def client():
+	if len(sys.argv) < 3:
+		usage()
+	host = sys.argv[2]
+	if len(sys.argv) > 3:
+		port = eval(sys.argv[3])
+	else:
+		port = ECHO_PORT
+	addr = host, port
+	s = socket(AF_INET, SOCK_DGRAM)
+	s.bind('', 0)
+	print 'udp echo client ready, reading stdin'
+	while 1:
+		line = sys.stdin.readline()
+		if not line:
+			break
+		s.sendto(line, addr)
+		data, fromaddr = s.recvfrom(BUFSIZE)
+		print 'client received', `data`, 'from', `fromaddr`
+
+main()