Create the server for the Chatroom program. This version has the username and chatroom changer implemented.
This commit is contained in:
parent
15313276bb
commit
5443d01d5c
3 changed files with 142 additions and 3 deletions
|
|
@ -1,11 +1,11 @@
|
||||||
# Running the chatserver
|
# Running the chatserver
|
||||||
TBA
|
Use `python server.py` to run the server
|
||||||
|
|
||||||
## chatserver communication
|
## chatserver communication
|
||||||
Use the client to communicate with the chatserver
|
Use the client to communicate with the chatserver by running `python client.py`
|
||||||
|
|
||||||
## chatserver information
|
## chatserver information
|
||||||
TBA
|
Included is the server and client written in Python.
|
||||||
|
|
||||||
## pcap information
|
## pcap information
|
||||||
A demonstration of the chatserver has been captured with Wireshark in the
|
A demonstration of the chatserver has been captured with Wireshark in the
|
||||||
|
|
|
||||||
0
chatserver/client.py
Normal file
0
chatserver/client.py
Normal file
139
chatserver/server.py
Normal file
139
chatserver/server.py
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
import socket
|
||||||
|
import select
|
||||||
|
|
||||||
|
CHATPORT = 8181
|
||||||
|
BUFFER_SIZE = 1024
|
||||||
|
MAX_CONNECT_QUEUE = 10
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# set the flag variable to true for infinite loop
|
||||||
|
quitFlag = True
|
||||||
|
# create a socket object
|
||||||
|
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
# set the socket options, SO_REUSEADDR allows to reuse the same port
|
||||||
|
# SO_KEEPALIVE enables the socket to send keepalive messages
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
|
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||||
|
# bind the socket to the address and port
|
||||||
|
server_socket.bind(('', CHATPORT))
|
||||||
|
# listen for incoming connections
|
||||||
|
server_socket.listen(MAX_CONNECT_QUEUE)
|
||||||
|
# set the server socket to non-blocking
|
||||||
|
server_socket.setblocking(False)
|
||||||
|
|
||||||
|
# create a list to store the sockets, server and client
|
||||||
|
socket_list = [server_socket]
|
||||||
|
# since a socket is associated with a username and a chatroom,
|
||||||
|
# and each one can only be associated one way at once, use dictionaries to
|
||||||
|
# associate with each other.
|
||||||
|
usernames = {}
|
||||||
|
chat_rooms = {}
|
||||||
|
# keep track of the states of each client connected, and if they are
|
||||||
|
# technically in an 'unsafe' state like in change username or chatroom mode.
|
||||||
|
client_states = {}
|
||||||
|
# let the user know the server is listening on port CHATPORT.
|
||||||
|
print(f"Chatserver listening on port: {CHATPORT}")
|
||||||
|
|
||||||
|
# infinite loop for the program
|
||||||
|
while quitFlag:
|
||||||
|
# use the select function to monitor the sockets
|
||||||
|
read_sockets, _, _ = select.select(socket_list, [], [])
|
||||||
|
# loop through the sockets
|
||||||
|
for sock in read_sockets:
|
||||||
|
# if the socket is the server socket, accept the connection
|
||||||
|
if sock == server_socket:
|
||||||
|
client_socket, client_address = server_socket.accept()
|
||||||
|
client_socket.setblocking(False)
|
||||||
|
socket_list.append(client_socket)
|
||||||
|
print("\nAccepted connection from new client.")
|
||||||
|
client_socket.send(b"\nWelcome to the chat server!\n")
|
||||||
|
client_socket.send(b"\nUse '%!' to exit, or '%?' for help.\n")
|
||||||
|
client_socket.send(b"\nType in a username: \n")
|
||||||
|
client_states[client_socket] = "WAITING_FOR_USERNAME"
|
||||||
|
# otherwise the socket is a client socket.
|
||||||
|
else:
|
||||||
|
# try to receive the message from the client
|
||||||
|
try:
|
||||||
|
message = sock.recv(BUFFER_SIZE).decode('utf-8')
|
||||||
|
if message:
|
||||||
|
state = client_states.get(sock, "NORMAL")
|
||||||
|
if state == "WAITING_FOR_USERNAME":
|
||||||
|
usernames[sock] = message.strip()
|
||||||
|
chat_rooms[sock] = "default"
|
||||||
|
sock.send(b"\nUsername accepted. You are now in the 'default' chatroom.\n")
|
||||||
|
client_states[sock] = "NORMAL"
|
||||||
|
elif state == "WAITING_FOR_NEW_USERNAME":
|
||||||
|
usernames[sock] = message.strip()
|
||||||
|
sock.send(b"\nUsername changed successfully.\n")
|
||||||
|
print(f"\nClient switched username to {usernames[sock]}.")
|
||||||
|
client_states[sock] = "NORMAL"
|
||||||
|
elif state == "WAITING_FOR_NEW_CHATROOM":
|
||||||
|
old_chatroom = chat_rooms[sock]
|
||||||
|
chat_rooms[sock] = message.strip()
|
||||||
|
sock.send(f"\nSwitched to chatroom '{chat_rooms[sock]}.'\n".encode('utf-8'))
|
||||||
|
print(f"\nClient switched to chatroom '{chat_rooms[sock]}.'")
|
||||||
|
if old_chatroom != "default" and old_chatroom not in chat_rooms.values():
|
||||||
|
print(f"\nChatroom '{old_chatroom}' is empty and removed.")
|
||||||
|
client_states[sock] = "NORMAL"
|
||||||
|
else:
|
||||||
|
if message.strip() == "%!":
|
||||||
|
sock.close()
|
||||||
|
socket_list.remove(sock)
|
||||||
|
del usernames[sock]
|
||||||
|
del chat_rooms[sock]
|
||||||
|
del client_states[sock]
|
||||||
|
print("\nClient has closed connection.")
|
||||||
|
elif message.strip() == "%?":
|
||||||
|
print("\nClient requested help.")
|
||||||
|
sock.send(b"Help: (%?)\n")
|
||||||
|
sock.send(b"Send messages like normal. Use enter to send a message.\n")
|
||||||
|
sock.send(b"Available Commands:\n")
|
||||||
|
sock.send(b"\t%? : Show this help prompt.\n")
|
||||||
|
sock.send(b"\t%! : Exit from the Chat Server.\n")
|
||||||
|
sock.send(b"\t%* : Switch to another chatroom.\n")
|
||||||
|
sock.send(b"\t%$ : Change Username.\n")
|
||||||
|
elif message.strip() == "%*":
|
||||||
|
sock.send(b"\nEnter chatroom name: \n")
|
||||||
|
client_states[sock] = "WAITING_FOR_NEW_CHATROOM"
|
||||||
|
elif message.strip() == "%$":
|
||||||
|
sock.send(b"\nEnter new username: \n")
|
||||||
|
client_states[sock] = "WAITING_FOR_NEW_USERNAME"
|
||||||
|
else:
|
||||||
|
username = usernames[sock]
|
||||||
|
chat_room = chat_rooms[sock]
|
||||||
|
send_message = f"{username} >> {message}".encode('utf-8')
|
||||||
|
for client_sock in socket_list:
|
||||||
|
if client_sock != server_socket and chat_rooms.get(client_sock) == chat_room:
|
||||||
|
client_sock.send(send_message)
|
||||||
|
else:
|
||||||
|
sock.close()
|
||||||
|
socket_list.remove(sock)
|
||||||
|
if sock in usernames:
|
||||||
|
del usernames[sock]
|
||||||
|
if sock in chat_rooms:
|
||||||
|
old_chatroom = chat_rooms[sock]
|
||||||
|
del chat_rooms[sock]
|
||||||
|
if old_chatroom != "default" and old_chatroom not in chat_rooms.values():
|
||||||
|
print(f"\nChatroom '{old_chatroom}' is empty and has been removed.")
|
||||||
|
if sock in client_states:
|
||||||
|
del client_states[sock]
|
||||||
|
print("\nClient has closed connection.")
|
||||||
|
except Exception as err:
|
||||||
|
print(f"Error: {err}")
|
||||||
|
sock.close()
|
||||||
|
socket_list.remove(sock)
|
||||||
|
if sock in usernames:
|
||||||
|
del usernames[sock]
|
||||||
|
if sock in chat_rooms:
|
||||||
|
old_chatroom = chat_rooms[sock]
|
||||||
|
del chat_rooms[sock]
|
||||||
|
if old_chatroom != "default" and old_chatroom not in chat_rooms.values():
|
||||||
|
print(f"\nChatroom '{old_chatroom}' is empty and has been removed.")
|
||||||
|
if sock in client_states:
|
||||||
|
del client_states[sock]
|
||||||
|
print("\nClient has closed connection.")
|
||||||
|
|
||||||
|
server_socket.close()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue