private void main() throws IOException {
		while (true) {
			byte[] data = new byte[Constants.MAX_UDP_BYTE_READ_SIZE];
			DatagramPacket packet = new DatagramPacket(data, data.length);
			localSocket.receive(packet);

			MessageHeader header = new MessageHeader(packet);
			Message message = messageFactory.buildMessageFromPacket(packet);

			if (message == null) {
				continue;
			}

			if (message instanceof AckMessage) {
				AckMessage ackMessage = (AckMessage)message;
				inAcknowledgements.add(ackMessage);
				Util.log("    === RECEIVE ACK for message " + ackMessage.getAckMsgId());
				continue;
			}

	        boolean messageOkay = false;
			int senderId = message.getSenderId();
	        int seqNumber = message.getSeqNumber();
	        Integer prevSeqNumber = senderSequenceNumbers.get(senderId);

	        if (senderId == Constants.UNASSIGNED_CLIENT_ID) {
	        	// Client is registering for the first time, so they have no senderId
	        	messageOkay = true;
	        } else if (message.isReliable() && !reliablyReceivedMessages.contains(message.hashKey())) {
				// Process the message only if we've never received it before
				messageOkay = true;
				reliablyReceivedMessages.add(message.hashKey());
				netManager.sendMessageAcknowledgement(message);
			} else {
		        // TODO: Handling overflowing sequence numbers
				// Non reliable messages are only processed if it's more recent than the last message
				if (prevSeqNumber == null || prevSeqNumber.intValue() < seqNumber) {
					messageOkay = true;
			        senderSequenceNumbers.put(senderId, seqNumber);
				}
			}

			if (messageOkay) {
				Util.log("    === RECEIVE [" + message.getSenderId() + " -> " + message.getReceiverId() + "]| " + message.getMessageId() + " [TYPE: " + header.getMessageType() + "] [SIZE: " + packet.getLength() + "]");
				inMessages.add(message);
			}
		}
	}