-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathchat_server.py
More file actions
124 lines (99 loc) · 3.67 KB
/
chat_server.py
File metadata and controls
124 lines (99 loc) · 3.67 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
#!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 = []
# 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.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
# Also set the appropriate name based on connection order.
self.name = "Client Y" if x.name == "Client X" else "Client X"
else: self.name = "Client X"
def connection_handler(client):
# Read data from the new connection socket.
# Note: if no data has been sent, this blocks until there is data available.
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
# Log query information.
log.info("Received query test \"" + str(query_decoded) + "\"")
# Append client name to message.
response = client.name + ": " + query_decoded
client.receive_buffer.append(response)
print("Response:", response)
print(client.receive_buffer)
# Client has now said bye. 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:
client.socket.send(client.send_buffer.pop(0).encode())
print("Response sent")
except OSError as e:
log.info("Client socket no longer open")
time.sleep(0.5)
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)
log.info("Connected to {} at {}".format(new_client.name, str(address)))
clients.append(new_client)
# 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()