public void connect(String address, int port) throws CouldNotConnectException {
		logger.fine("Connecting to " + address + ":" + port + "...");
		boolean disconnected = false;
		try {
			synchronized(CONNECTION_LOCK) {
				if(isConnected) {
					logger.fine("Disconnecting from " + serverAddress + ":" + serverPort + " so client can connect to " + address + ":" + port);
					disconnectQuietly();
					disconnected = true;
				}
				else if(isAttemptingToConnect) {
					logger.fine("Cancelling connect request to " + serverAddress + ":" + serverPort + " so client can connect to " + address + ":" + port);
					closeConnection();
				}
				isAttemptingToConnect = true;
				serverAddress = address;
				serverInetAddress = InetAddress.getByName(serverAddress);
				serverPort = port;
				socket = new DatagramSocket();
				receivePacketThread = new ReceivePacketThread(this, socket);
				receivePacketThread.start();
				timeoutThread = new TimeoutThread(this, ClientConnection.CONNECT_REQUEST_TIMEOUT);
				timeoutThread.start();
				logger.finer("Sending connect request packet");
				sendPacket(Packet.createConnectRequestPacket());
			}
		} catch (UnknownHostException e) {
			closeConnection();
			logger.fine("Could not connect due to UnknownHostException: " + e.getMessage());
			throw new ServerNotFoundException(address, port); //wrapped so callers can just catch CouldNotConnectException
		} catch (SocketException e) {
			closeConnection();
			logger.fine("Could not connect due to SocketException: " + e.getMessage());
			throw new CouldNotOpenSocketToServerException(e);
		} catch (CouldNotSendPacketException e) {
			closeConnection();
			logger.fine("Could not connect due to CouldNotSendPacketException while sending connect request: " + e.getMessage());
			throw new CouldNotSendConnectRequestException(e);
		}
		finally {
			if(disconnected) {
				onDisconnected(ClientConnection.DISCONNECTED_BY_CLIENT);
			}
		}
	}