· 8 years ago · Dec 10, 2017, 10:46 PM
1using System.Linq;
2using System;
3using System.Collections.Generic;
4using System.Text;
5using System.Net;
6using System.Net.Sockets;
7using System.IO;
8using System.Threading;
9using System.Collections;
10
11
12namespace UnityChatTestServer1
13{
14
15 // Holds the arguments for the StatusChanged event
16 public class StatusChangedEventArgs : EventArgs
17 {
18 // The argument we're interested in is a message describing the event
19 private string EventMsg;
20
21 // Property for retrieving and setting the event message
22 public string EventMessage
23 {
24 get
25 {
26 return EventMsg;
27 }
28 set
29 {
30 EventMsg = value;
31 }
32 }
33
34 // Constructor for setting the event message
35 public StatusChangedEventArgs(string strEventMsg)
36 {
37 EventMsg = strEventMsg;
38 }
39 }
40
41 // This delegate is needed to specify the parameters we're passing with our event
42 public delegate void StatusChangedEventHandler(object sender, StatusChangedEventArgs e);
43
44 class ChatServer
45 {
46 // This hash table stores users and connections (browsable by user)
47 public static Hashtable htUsers = new Hashtable(30); // 30 users at one time limit
48
49 // This hash table stores connections and users (browsable by connection)
50 public static Hashtable htConnections = new Hashtable(30); // 30 users at one time limit
51
52 // Will store the IP address passed to it
53 private IPAddress ipAddress;
54 private TcpClient tcpClient;
55
56 // The event and its argument will notify the form when a user has connected, disconnected, send message, etc.
57 public static event StatusChangedEventHandler StatusChanged;
58 private static StatusChangedEventArgs e;
59
60 // The constructor sets the IP address to the one retrieved by the instantiating object
61 public ChatServer(IPAddress address)
62 {
63 ipAddress = address;
64 }
65
66 // The thread that will hold the connection listener
67 private Thread thrListener;
68
69 // The TCP object that listens for connections
70 private TcpListener tlsClient;
71
72 // Will tell the while loop to keep monitoring for connections
73 bool ServRunning = false;
74
75 // Add the user to the hash tables
76 public static void AddUser(TcpClient tcpUser, string strUsername)
77 {
78 // First add the username and associated connection to both hash tables
79 ChatServer.htUsers.Add(strUsername, tcpUser);
80 ChatServer.htConnections.Add(tcpUser, strUsername);
81
82 // Tell of the new connection to all other users and to the server form
83 SendAdminMessage(htConnections[tcpUser] + " has joined us");
84 }
85
86 // Remove the user from the hash tables
87 public static void RemoveUser(TcpClient tcpUser)
88 {
89 // If the user is there
90 if (htConnections[tcpUser] != null)
91 {
92 // First show the information and tell the other users about the disconnection
93 SendAdminMessage(htConnections[tcpUser] + " has left us");
94
95 // Remove the user from the hash table
96 ChatServer.htUsers.Remove(ChatServer.htConnections[tcpUser]);
97 ChatServer.htConnections.Remove(tcpUser);
98 }
99 }
100
101 // This is called when we want to raise the StatusChanged event
102 public static void OnStatusChanged(StatusChangedEventArgs e)
103 {
104 StatusChangedEventHandler statusHandler = StatusChanged;
105 if (statusHandler != null)
106 {
107 // Invoke the delegate
108 statusHandler(null, e);
109 }
110 }
111
112 // Send administrative messages
113 public static void SendAdminMessage(string Message)
114 {
115 StreamWriter swSenderSender;
116
117 // First of all, show in our application who says what
118 e = new StatusChangedEventArgs("Administrator: " + Message);
119 OnStatusChanged(e);
120
121 // Create an array of TCP clients, the size of the number of users we have
122 TcpClient[] tcpClients = new TcpClient[ChatServer.htUsers.Count];
123
124 // Copy the TcpClient objects into the array
125 ChatServer.htUsers.Values.CopyTo(tcpClients, 0);
126
127 // Loop through the list of TCP clients
128 for (int i = 0; i < tcpClients.Length; i++)
129 {
130 // Try sending a message to each
131 try
132 {
133 // If the message is blank or the connection is null, break out
134 if (Message.Trim() == "" || tcpClients[i] == null)
135 {
136 continue;
137 }
138
139 // Send the message to the current user in the loop
140 swSenderSender = new StreamWriter(tcpClients[i].GetStream());
141 swSenderSender.WriteLine("Administrator: " + Message);
142 swSenderSender.Flush();
143 swSenderSender = null;
144 }
145
146 catch // If there was a problem, the user is not there anymore, remove him
147 {
148 RemoveUser(tcpClients[i]);
149 }
150 }
151 }
152
153 // Send messages from one user to all the others
154 public static void SendMessage(string From, string Message)
155 {
156 StreamWriter swSenderSender;
157
158 // First of all, show in our application who says what
159 e = new StatusChangedEventArgs(From + " says: " + Message);
160 OnStatusChanged(e);
161
162 // Create an array of TCP clients, the size of the number of users we have
163 TcpClient[] tcpClients = new TcpClient[ChatServer.htUsers.Count];
164
165 // Copy the TcpClient objects into the array
166 ChatServer.htUsers.Values.CopyTo(tcpClients, 0);
167
168 // Loop through the list of TCP clients
169 for (int i = 0; i < tcpClients.Length; i++)
170 {
171 // Try sending a message to each
172 try
173 {
174 // If the message is blank or the connection is null, break out
175 if (Message.Trim() == "" || tcpClients[i] == null)
176 {
177 continue;
178 }
179
180 // Send the message to the current user in the loop
181 swSenderSender = new StreamWriter(tcpClients[i].GetStream());
182 swSenderSender.WriteLine(From + " says: " + Message);
183 swSenderSender.Flush();
184 swSenderSender = null;
185 }
186 catch // If there was a problem, the user is not there anymore, remove him
187 {
188 RemoveUser(tcpClients[i]);
189 }
190 }
191 }
192
193 public void StartListening()
194 {
195 // Get the IP of the first network device, however this can prove unreliable on certain configurations
196 IPAddress ipaLocal = ipAddress;
197
198 // Create the TCP listener object using the IP of the server and the specified port
199 TcpListener tlsClient = new TcpListener(ipAddress, 1986);
200
201 // Start the TCP listener and listen for connections
202 tlsClient.Start();
203
204 // The while loop will check for true in this before checking for connections
205 ServRunning = true;
206
207 // Start the new tread that hosts the listener
208 thrListener = new Thread(KeepListening);
209 thrListener.Start();
210 }
211
212 private void KeepListening()
213 {
214 // While the server is running
215 while (ServRunning == true)
216 {
217 // Accept a pending connection
218 tcpClient = tlsClient.AcceptTcpClient();
219
220 // Create a new instance of Connection
221 Connection newConnection = new Connection(tcpClient);
222 }
223 }
224 }
225
226 // This class handels connections; there will be as many instances of it as there will be connected users
227 class Connection
228 {
229 TcpClient tcpClient;
230
231 // The thread that will send information to the client
232 private Thread thrSender;
233 private StreamReader srReceiver;
234 private StreamWriter swSender;
235 private string currUser;
236 private string strResponse;
237
238 // The constructor of the class takes in a TCP connection
239 public Connection(TcpClient tcpCon)
240 {
241 tcpClient = tcpCon;
242
243 // The thread that accepts the client and awaits messages
244 thrSender = new Thread(AcceptClient);
245
246 // The thread calls the AcceptClient() method
247 thrSender.Start();
248 }
249
250 private void CloseConnection()
251 {
252 // Close the currently open objects
253 tcpClient.Close();
254 srReceiver.Close();
255 swSender.Close();
256 }
257
258 // Occures when a new client is accepted
259 private void AcceptClient()
260 {
261 srReceiver = new System.IO.StreamReader(tcpClient.GetStream());
262 swSender = new System.IO.StreamWriter(tcpClient.GetStream());
263
264 // Read the account information from the client
265 currUser = srReceiver.ReadLine();
266
267 // We got a response from the client
268 if (currUser != "")
269 {
270 // Store the user name in the hash table
271 if (ChatServer.htUsers.Contains(currUser) == true)
272 {
273 // 0 means not connected
274 swSender.WriteLine("0|This username already exists.");
275 swSender.Flush();
276 CloseConnection();
277 return;
278 }
279 else if (currUser == "Administrator")
280 {
281 // 0 means not connected
282 swSender.WriteLine("0|This username is reserved.");
283 swSender.Flush();
284 CloseConnection();
285 return;
286 }
287 else
288 {
289 // 1 means connected successfully
290 swSender.WriteLine("1");
291 swSender.Flush();
292
293 // Add the user to the hash tables and start listening for messages from him
294 ChatServer.AddUser(tcpClient, currUser);
295 }
296 }
297 else
298 {
299 CloseConnection();
300 return;
301 }
302
303 try
304 {
305 // Keep waiting for a message from the user
306 while ((strResponse = srReceiver.ReadLine()) != "")
307 {
308 // If it's invalid, remove the user
309 if (strResponse == null)
310 {
311 ChatServer.RemoveUser(tcpClient);
312 }
313 else
314 {
315 // Otherwise send the message to all the other users
316 ChatServer.SendMessage(currUser, strResponse);
317 }
318 }
319 }
320 catch
321 {
322 // If anything went wrong with this user, disconnect him
323 ChatServer.RemoveUser(tcpClient);
324 }
325 }
326 }
327}