Download as pdf or txt
Download as pdf or txt
You are on page 1of 21

Programming Assignment #3

CST 311, Introduction to Computer Networks, Spring 2020


February 18, 2018

Team Members:

Name Role

Holly Stephens Co-leader


code reviewer, documentation

Roger Chicas-Terrill Co-leader


server-side and client-side programming, test plan, testing

Carlos Orduna Co-leader


code reviewer, testing, documentation

George Blombach Co-leader


server-side and client-side programming, testing, documentation

Pseudocode

Roger Chicas-Terrill

Server
- Create socket
- Loop
- Accept connections
- Message that connection is set and ask for name
- Create a thread
- Assign thread to each conversation
- while message is not bye, check messenger
- broadcast message of status
- else
- show user has left message
- once done close the server connection
Client
- setup sockets
- setup threads
- constantly ask for input
- send message
- receive message from server

Carlos Orduna
Server

Create socket
Assign IP and port to socket
Socket listener for client input
While no Bye msg
receive address
verify who sent message
receive client response
forward response
loop while
disconnect session
close socket

Client

var = host to connect


port = port to connect
Create socket
Connect socket to server
msg = empty
while no Bye msg
input sentence
send to server
print answer
loop while
close socket
Holly Stephens

Server:
create a server socket
create a thread
receive connections loop:
for each connection:
create new thread
while message != 'bye':
receive message
broadcast message

disconnect session
close socket

Client:
create a socket and initialize variables
create a thread for message reception
while message != 'bye':
read keyboard input
send to server
print response
close socket

George Blombach

Server

Setup server socket


Start server socket listener
Spawn thread for accepting connections
For each client socket connection
Store socket and name in tuple
Spawn thread to client for communication
For first message received from two connected clients
Determine who sent the message first
Broadcast which client message was received first
For each message received from client
Loop through socket tuple and broadcast message to all clients
If client message is “bye”
Disconnect client session (but leave the others)

Client

Setup server socket parameters


Create socket connection to server
Spawn thread to receive messages from server
Loop keyboard input
Send message
If message is “bye”
Close socket
Basis of Decision
The basis for the program design was derived from the following requirements detailed
in the programming assignment:

Requirements for Design

1. Clients must connect using TCP socket connection (rubric #1)..


2. Clients must initiate the connection (rubric #2).
3. Server receives messages from both clients and establishes which message it
received first (rubric #3).
4. Server sends acknowledgements to both clients stating which message was
received first (rubric #4).
5. The server must accept connections from both clients first before receiving the
messages from either client (rubric #5)
6. The response string from Server to Clients (“X: Alice received before Y: Bob”, or
“Y: Bob received before X: Alice”) must be in the order the messages from Client
X or Client Y are received and NOT the order in which the clients X and Y
connected to the server (rubric #6).
7. Messages sent by the client should print at both the client and server and vice
versa for messages sent by the server (rubric #7).
8. N​ number of clients can connect to server to the chat server, and the server
relays messages back to all clients (extra credit #1)
9. Clients can disconnect from service by typing “bye” as the server will drop their
connection (extra Credit #2)
10. Clients must be able to output messages sent to it from other clients (extra credit
#3)
11. Clients must be able to accept input from the keyboard (extra credit #3)
Design Specifications

1. Client-Server chat designed to support any number of clients


2. To meet the assignment requirements, only the first two client connections are
evaluated for who sent a message first
3. Only the first message from the two connections is evaluated
4. Client socket connections are stored in global tuple
5. Clients can disconnect by sending “bye” to the server
6. Threads can share data in the heap via a global variable (Bool). This will be used
to determine which client sent the first message.
7. The first client connected will be X and the second client connected will be Y.
These are independent of the names of the chat users.
8. Each client can enter their name identifier to be used by the chat service.
Network Steps

1. create server socket


○ serverPort = 12021
2. create client socket
○ serverName = 'localhost'
○ serverPort = 12021

Sockets are created using socket(AF_INET, SOCK_STREAM). The first parameter indicates
the network is using IPv4. The second parameter indicates the socket type, specifically, a
TCP socket is being used in this case. Note that in order for data to be exchanged between
a client and a server using a TCP socket, a connection must first be established.

The server dictates where the clients need to connect (in our case localhost). The server
listens on a specific port for clients to connect to. Upon connection, the server assigns a
socket to the client's address and once the client disconnects, the socket is closed.
Testing

Test Plan
a. Alice first establishes TCP connects with server, Alice sends first message
b. Alice first establishes TCP connects with server, Bob sends first message
c. Bob first establishes TCP connects with server, Alice sends first message
d. Bob first establishes TCP connects with server, Bob sends first message

NOTE: We implemented a sequential assignment of X and Y to the first and second connected
clients, respectively, so the test plan differs slightly from the assignment instructions. However,
our software design and testing will still show that the connection sequence of the clients is
detached from the sending and receiving of messages from those clients.

Test Results

Testing was performed by each of the team members. The results of each test was consistent
with the ​Results​ screenshots included herein.

The program design using sockets and thread ensured that the connection of the client was
detached from the randomness of message communication between clients.

Initial testing revealed a difference in code requirements for Python 3, which was the team’s
development platform, and Python 2, which was available in the Mininet virtual machine. The
code was adjusted to accommodate the Mininet environment, both versions of the code are
provided ​below​.

All test results were conclusive and representative of the project goals and expectations.
Interesting Findings
1. The global checkPoint (Bool) variable had to be declared in the While loop within the
function, but the other global variable for clients (OrderedDict) did not have be declared

2. Our initial code was written in Python 3, because this is an industry standard and Python
2 is End of Life. However, we encountered issues with syntax difference between the
two platforms and during code review and testing we needed to adjust some of the code.
Both versions of the code have been submitted in this assignment.
a. client.send(bytes('You are connected to chat. Type "bye" to quit.',​encoding​)) →
client.send(bytes('Connected to chat server. Enter your name and press
enter.')​.encode(encoding)​)
b. Input → ​raw_​input

3. We implemented the client X and Y assignment in a way that seemed to make sense to
us, assigning X to the first connection and Y to the second. However, the testing plan
included both a letter identifier and and name identifier. We implemented these both
independently of each other, so the first client connecting wout be X, but the user could
be Alice or Bob or someone else. This altered the test plan slightly from the assignment
description, but it also made the X and Y identifier redunant. In actuallity, there are only
two scenarios that need to be tested:
a. Client 1 connecting first, and Client 1 sending a message after client 2 joins
b. Client 1 connecting first, and Client 2 sending a message after connecting

The other two scenarios are just mirror images of the first two, and are redundant.
 

Results

Test Plan 1:
Test Plan 2:
Test Plan 3:
Test Plan 4:
 

Final Code : Python 3

Server
Client
Final Code : Python 2 (use with mininet)

Server

# Blombach, Chicas-Terrill, Orduna, Stephens


# TCPChatServer.py
# February 18, 2020

from​ socket ​import​ ​*


from​ threading ​import​ ​Thread
import​ collections
import​ time

# variables
serverName ​=​''
serverPort ​=​ ​12021
messageSize ​=​ ​1024
clients ​=​ collections.​OrderedDict​()
encoding ​=​'utf8'
checkPoint ​=​ ​False
order ​=​[​'X'​,​'Y'​]

# Create a TCP socket and bind to server port


# Notice the use of SOCK_STREAM for TCP packets
serverSocket ​=​ ​socket​(​AF_INET​,​SOCK_STREAM​)
serverSocket.​bind​((serverName,serverPort))

#function for accepting connections to the server


def​ ​acceptConnection​():
​while​ ​True​:
client, clientAddress ​=​ serverSocket.​accept​()
​print​(​'%s:%s has connected'​ ​%​ clientAddress)
client.​send​(​bytes​(​'Connected to chat server. Enter your name and press
enter.'​).​encode​(encoding))
​Thread​(target​=​clientChat, args​=​(client,clientAddress)).​start​()

#function for receiving messages from clients


def​ ​clientChat​(client,clientAddress):
name ​=​ client.​recv​(messageSize).​decode​()
​#store sockets in tuple
clients[client] ​=​ name
client.​send​(​bytes​(​'You are connected to chat. Type "bye" to
quit.'​).​encode​(encoding))
message ​=​ ​'System: %s has joined chat.'​ ​%​ name
​#send chat connection information to all clients
​broadcast​(​bytes​(message).​encode​(encoding))

​while​ ​True​:
​#instantiate global variable
​global​ checkPoint
​#get message from client
message ​=​ client.​recv​(messageSize)
​#if the message is not a disconnect request
​if​ message ​!=​bytes​(​'bye'​).​encode​(encoding):
​#check who sent the message first
​#only when two people have been connected to the system
​if​ checkPoint ​==​ ​False​ ​and​ ​len​(clients) ​==​ ​2​:
checkPoint ​=​ ​True
statusMessage ​=​ ​'*** '​ ​+
order[​list​(clients.​values​()).​index​(name)] ​+​ ​': '​ ​+​\
name ​+​ ​' received before '​ ​+
order[(​list​(clients.​values​()).​index​(name) ​+​ ​1​) ​%​ ​len​(clients)] ​+​\
​': '​ ​+​ ​list​(clients.​values​())[
(​list​(clients.​values​()).​index​(name) ​+​ ​1​) ​%​ ​len​(clients)] ​+​ ​' ***'
​#send status message to all clients
​broadcast​(​bytes​(statusMessage).​encode​(encoding))

​broadcast​(message, name ​+​ ​': '​)


​#else disconnect
​else​:
client.​send​(​bytes​(​'System: Bye, '​ ​+​ name).​encode​(encoding))
​broadcast​(​bytes​(​'System: %s has left chat.'​ ​%​ name).​encode​(encoding))
​#close connection
time.​sleep​(​2​)
client.​close​()
​#log disconnect on server console
​print​(​'%s:%s has disconnected'​ ​%​ clientAddress)
​#remove client socket from ordered list
​del​ clients[client]
​break

#function to broadcast messages to all connected clients


def​ ​broadcast​(message,prefix​=​''​):

​#send message to all clients


​for​ sockets ​in​ clients:
sockets.​send​(​bytes​(prefix).​encode​(encoding)​+​ message)

​#send message to server too


​print​((​bytes​(prefix).​encode​(encoding)​+​ message).​decode​())

# main function that establishes socket listener


def​ ​Main​():

serverSocket.​listen​(​1​)
​print​(​'waiting for connections'​)
newThread ​=​ ​Thread​(target​=​acceptConnection)
newThread.​start​()
newThread.​join​()

​#close the connection


serverSocket.​close​()

#run main
if​ __name__ ​==​ ​'__main__'​:
​Main​()

Client
# Programming Assignment 3
# Blombach, Chicas-Terrill, Orduna, Stephens
# TCPChatClient.py
# February 18, 2020

from​ socket ​import​ ​*


from​ threading ​import​ ​Thread
import​ time

# variables
serverName ​=​ ​'localhost'
serverPort ​=​ ​12021
messageSize ​=​ ​1024
encoding ​=​'utf8'

# function to receive messages through client socket


def​ ​receiveMessage​():
​while​ ​True​:
​try​:
message ​=​ clientSocket.​recv​(messageSize)
​print​(message.​decode​())

​except​ ​Exception​ ​as​ e:


​print​(e)
​break

# function to send messages via client socket


def​ ​sendMessage​(event​=None​):
clientSocket.​send​(​bytes​(message).​encode​(encoding))
# run main routine
if​ __name__ ​==​ ​'__main__'​:

​#setup client socket to server


clientSocket ​=​ ​socket​(​AF_INET​, ​SOCK_STREAM​)
clientSocket.​connect​((serverName,serverPort))

​#create thread to receive messages via function


receiveThread ​=​ ​Thread​(target​=​receiveMessage)
receiveThread.​start​()
​#loop keyboard input
​while​ ​True​:
message ​=​ ​raw_input​(​''​)
​sendMessage​()
​#if client wants to quit, then break loop
​if​ message ​==​ ​'bye'​:
time.​sleep​(​3​)
​break
​#close connection
clientSocket.​close​()

You might also like