-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchat_server_ec.py
More file actions
138 lines (108 loc) · 4.08 KB
/
chat_server_ec.py
File metadata and controls
138 lines (108 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!env python
"""Chat server for CST311 Programming Assignment 3"""
__author__ = "Team 2"
__credits__ = [
"Henry Garkanian",
"Ivan Soria",
"Kyle Stefun",
"Bryan Zanoli"
]
import socket as s
import time
import _thread
clients = []
pending_messages = []
# Configure logging
import logging
logging.basicConfig()
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
server_port = 12000
#Defined class that inhibits every trait used in the socket buffer.
class Client:
def __init__(self, address, socket):
self.name = ""
self.address = address
self.socket = socket
self.send_buffer = []
self.receive_buffer = []
self.connected = True
# If this isn't the first client, set the receive buffer of both clients to the other's send buffer.
if (len(clients) > 0):
for x in clients:
if x != self:
self.receive_buffer = x.send_buffer
x.receive_buffer = self.send_buffer
def connection_handler(client):
# Reads data from the new connection socket.
# Note: if no data has been sent, this blocks until there is data available.
# Ask for client username.
client_name = client.socket.recv(1024)
#Set client username to provided value.
client.name = client_name.decode()
log.info("Connected to {} at {}".format(client.name, str(client.address)))
# Send client its username as confirmation.
client.socket.send(client.name.encode())
clients.append(client)
# Put any pending messages into the send buffer.
while len(pending_messages) > 0:
client.send_buffer.append(pending_messages.pop(0))
while True:
query = client.socket.recv(1024)
# Decode data from UTF-8 bytestream.
query_decoded = query.decode()
# Client has disconnected - exit this thread's loop.
if not query or query_decoded == "bye":
break
# Append client name to message and insert null terminator to avoid clientside concatenation of multiple messages.
response = client.name + ": " + query_decoded + "\0"
# If only one client is connected, save this message for later.
if len(clients) == 1:
pending_messages.append(response)
# Otherwise, put it in the message buffer to be sent in the broadcast loop.
else:
client.receive_buffer.append(response)
# Client has disconnected. Remove it from client list.
clients.remove(client)
# Close client socket
client.socket.close()
# Tell any other active clients that the client has left.
for x in clients:
x.socket.send("{} has left the chat.".format(client.name).encode())
def broadcast_loop():
# Send any messages that are pending.
while True:
for client in clients:
if len(client.send_buffer) > 0:
try:
while len(client.send_buffer) > 0:
client.socket.send(client.send_buffer.pop(0).encode())
except OSError as e:
log.info("Client socket no longer open")
time.sleep(0.2)
def main():
# Create a TCP socket.
# Notice the use of SOCK_STREAM for TCP packets.
server_socket = s.socket(s.AF_INET,s.SOCK_STREAM)
# Assign port number to socket, and bind to chosen port.
server_socket.bind(('',server_port))
# Configure how many requests can be queued on the server at once.
server_socket.listen(1)
# Alert user we are now online.
log.info("The server is ready to receive on port " + str(server_port))
# Start a thread to handle sending messages,
# because each client-specific thread will block as it waits for client input.
_thread.start_new_thread(broadcast_loop, ())
# Surround with a try-finally to ensure we clean up the socket after we're done.
try:
# Enter infinite while loop to listen for requests.
while True:
# When a client connects, create a new socket and record their address.
connection_socket, address = server_socket.accept()
new_client = Client(address, connection_socket)
# Pass the new socket and address off to a connection handler function in a new thread.
_thread.start_new_thread(connection_handler, (new_client,))
finally:
server_socket.close()
if __name__ == "__main__":
main()